Hawk High

First Flight #39
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Bursary is not updated after transferring teachers' and principal's wages, which leads to incorrect reported value in the upgraded contract

Summary

LevelTwo bursary is expected to be 60% of total submitted fees, but it shows a value of 100%. This is because the variable is never updated when deducting the staff wages.

Vulnerability Details

in LevelOne.graduateAndUpgrade(), some percentage of the bursary is paid to the principal and teachers. The total amount paid is 40% of the bursary which is followed by an upgrade of the contract. The upgraded contract's bursary variable should reflect the total balance of the contract which is 60% of the fees paid by all students. The staff wages are never deducted from bursary, leading to an incorrect value in the upgraded contract.
Relevant code:

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
uint256 totalTeachers = listOfTeachers.length;
uint256 payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION;
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION;
// update bursary here
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
}

Impact

Broken contract invariant: remaining 60% should reflect in the bursary after upgrade. Any future calculations based on the bursary would lead to an incorrect result.

Proof Of Concept

Run forge test --mt test_confirm_can_graduate -vvv.

function test_confirm_can_graduate() public schoolInSession {
levelTwoImplementation = new LevelTwo();
levelTwoImplementationAddress = address(levelTwoImplementation);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
LevelTwo levelTwoProxy = LevelTwo(proxyAddress);
// For 6 students: 100% = 3e22, 60% = 1.8e22 (actual balance = 0.75e22 but that is a different bug)
console2.log(levelTwoProxy.bursary()); // shows 3e22
console2.log(levelTwoProxy.getTotalStudents());

Expected Result:

Ran 1 test for test/LeveOnelAndGraduateTest.t.sol:LevelOneAndGraduateTest
[PASS] test_confirm_can_graduate() (gas: 1172920)
Logs:
30000000000000000000000
6
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.71ms (846.54µs CPU time)
Ran 1 test suite in 3.82ms (1.71ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Tools Used

Manual Review

Recommendation

Update the bursary after successful payments.

Updates

Lead Judging Commences

yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

bursary not updated

The bursary is not updated after wages have been paid in `graduateAndUpgrade()` function

yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

bursary not updated

The bursary is not updated after wages have been paid in `graduateAndUpgrade()` function

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.