Hawk High

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

`sessionEnd` Is Assigned But Never Used — Invariant Becomes Ineffective

Summary

The contract assigns a value to sessionEnd at the start of each session to represent the session's scheduled end timestamp. However, this variable is never referenced or enforced anywhere else in the protocol logic, rendering its existence meaningless and violating a stated invariant that prohibits upgrades before session end.

Vulnerability Details

According to the contract's documented invariants:

"System upgrade cannot take place unless school's sessionEnd has been reached"

However, the only reference to sessionEnd in the contract is its assignment in startSession():

function startSession(uint256 _cutOffScore) public onlyPrincipal notYetInSession {
sessionEnd = block.timestamp + 4 weeks; // assign here
inSession = true;
cutOffScore = _cutOffScore;
emit SchoolInSession(block.timestamp, sessionEnd);
}

Despite being recorded and emitted, sessionEnd is never used in a conditional check, not even in critical flows like graduateAndUpgrade() where it should gate the upgrade mechanism until the session truly ends.

As a result:

  • The system does not enforce the minimum 4-week session duration.

  • The graduateAndUpgrade() function could be called prematurely, contradicting the intended time-lock on upgrades.

  • Developers and auditors may falsely assume that time constraints are enforced, leading to misplaced trust in the contract logic.

Impact

  • Time-based control of session lifecycle is broken, violating upgrade constraints.

  • Students may graduate early, bypassing the expected 4-week duration.

  • Invariants become misleading, reducing protocol transparency and increasing audit risk.

Tools Used

  • Manual Code Review

  • Slither

Recommendations

  • Enforce the sessionEnd constraint explicitly in the graduateAndUpgrade() function, e.g.:

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
require(block.timestamp >= sessionEnd, "Session has not ended"); // fix
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
...
}
  • Consider auditing all time-based assumptions across the contract to ensure sessionEnd is meaningfully integrated into core logic.

Updates

Lead Judging Commences

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

session state not updated

`inSession` not updated after during upgrade

Support

FAQs

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