Hawk High

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

Breaking invariant - able to upgrade before session ends

Summary

In file LevelOne.sol function graduateAndUpgrade()

It is possible to upgrade the contract even if the session is active and not reaching the session end time

Vulnerability Details

In the graduateAndUpgrade function, there's no check if the sessionEnd time is reached.

A principle can perform upgrade with no sessionEnd requirement

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;
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
}

Proof of Concept

Add the following test within test/LeveOnelAndGraduateTest.t.sol

function test_confirm_can_graduate_before_session_ends()
public
schoolInSession
{
// prepare upgrade data
levelTwoImplementation = new LevelTwo();
levelTwoImplementationAddress = address(levelTwoImplementation);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
// make sure we are still in session
assertTrue(
levelOneProxy.getSessionStatus(),
"Session should be in progress"
);
// Make sure we are not hit the sessionEnd time
assertLt(
block.timestamp,
levelOneProxy.getSessionEnd(),
"Time should be before sessionEnd"
);
// Only passed a week only, should not able to graduate and upgrade!
vm.warp(block.timestamp + 1 weeks);
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
}

Outputs

forge test -vvv --match-test test_confirm_can_graduate_before_session_ends
[⠊] Compiling...
No files changed, compilation skipped
Ran 1 test for test/LeveOnelAndGraduateTest.t.sol:LevelOneAndGraduateTest
[PASS] test_confirm_can_graduate_before_session_ends() (gas: 1174058)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.16ms (2.27ms CPU time)
Ran 1 test suite in 132.04ms (13.16ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Impact

Invariant breaking -- System upgrade cannot take place unless school's sessionEnd has reached


Tools Used

Manual review


Recommendations

Considering adding the time check before perform upgrades

/// @dev only after session end time passed
modifier onlyAfterSession() {
if (!inSession || block.timestamp < sessionEnd) {
revert HH__SessionStillAlive(); // Or customized error
}
_;
}
function graduateAndUpgrade(address _levelTwo, bytes memory)
public
onlyPrincipal
onlyAfterSession
{
_authorizeUpgrade(_levelTwo);
}
Updates

Lead Judging Commences

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

can graduate without session end

`graduateAndUpgrade()` can be called successfully even when the school session has not ended

Support

FAQs

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