Hawk High

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

Missing Temporal Validation Enables Premature Contract Upgrades and Fund Distribution

Summary

The system allows upgrades to occur before the session end time, which breaks a critical security invariant in the contract design.

Vulnerability Details

The graduateAndUpgrade() function in the contract lacks a time-based check, allowing the system to upgrade to level two at any time during an active school session. This bypasses the intended restriction that upgrades should only happen after a session has ended.

function test_can_graduate_before_session_ends() public schoolInSession {
levelTwoImplementation = new LevelTwo();
levelTwoImplementationAddress = address(levelTwoImplementation);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
assert(levelOneProxy.sessionEnd() > block.timestamp); // time has not reached session end
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
}

Impact

This vulnerability allows the principal to prematurely trigger graduation and upgrade processes, potentially resulting in:

  • Unintended early distribution of funds to teachers and principal

  • Disruption of ongoing educational processes

  • Violation of user expectations regarding session timing

  • Potential exploitation of timing-dependent logic in connected systems

Tools Used

Manual review

Recommendations

Implement a time-based control in the graduateAndUpgrade() function to ensure upgrades can only occur after the session has formally ended:

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
+ require(block.timestamp >= sessionEnd, "Session has not ended yet");
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);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 6 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.