Hawk High

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

Premature Graduation Due to Missing Session End Check

Summary

The graduateAndUpgrade function does not validate that the school session has ended, allowing premature graduation and system upgrades, this violates a core invariant regardless of wether principal is trusted or not.

Vulnerability Details

Root Cause: The graduateAndUpgrade function lacks a check to verify block.timestamp >= sessionEnd, violating the core invariant that "System upgrade cannot take place unless school's sessionEnd has reached".

function graduateAndUpgrade(address _levelTwo, bytes memory data) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
// Missing check: require(block.timestamp >= sessionEnd, "Session not ended");
// ...rest of function
}

Initial State:

  • School session started

  • Session end time set

  • Students and teachers active

Attack Flow:

  1. Principal starts session with 4-week duration

  2. Principal can call graduateAndUpgradebefore 4 weeks duration

  3. Students lose opportunity to complete full session

  4. System upgrades before session properly ends

Impact

  • Sessions can be prematurely terminated

  • Students denied full learning period

  • Teachers denied opportunity to give all reviews

  • Core educational process compromised

  • Violates fundamental timing invariant

POC

function testPrematureGraduation() public {
// Setup
address student1 = makeAddr("student1");
address teacher1 = makeAddr("teacher1");
// Add teacher and enroll student
vm.prank(principal);
levelOneProxy.addTeacher(teacher1);
vm.startPrank(student1);
usdc.mint(student1, schoolFees);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
// Start session with 4 weeks duration
vm.prank(principal);
levelOneProxy.startSession(70);
uint256 sessionEndTime = levelOneProxy.getSessionEnd();
// Try to graduate immediately
levelTwoImplementation = new LevelTwo();
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
// Should revert but doesn't
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(address(levelTwoImplementation), data);
// Proves upgrade happened before session end
assert(block.timestamp < sessionEndTime);
}

Tools Used

Manual review

Recommendations

Add session end validation:

function graduateAndUpgrade(address _levelTwo, bytes memory data) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
if (block.timestamp < sessionEnd) {
revert HH__SessionNotEnded();
}
// ...rest of function
}
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

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.