Hawk High

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

Students Below Cutoff Score Can Graduate to Level Two

Summary

The graduateAndUpgrade function in the LevelOne contract fails to enforce the minimum cutoff score requirement when graduating students to Level Two. This critical vulnerability allows students with scores below the established cutoff to still graduate, undermining the entire educational merit system. Breaking the protocol invariant.

Vulnerability Details

When starting a session, the principal sets a cutoff score that should determine which students qualify for graduation:

function startSession(uint256 _cutOffScore) external onlyPrincipal {
if (inSession) {
revert HH__SessionOngoing();
}
inSession = true;
sessionEnd = block.timestamp + 4 weeks;
cutOffScore = _cutOffScore;
emit SessionStarted(sessionEnd);
}

However, in the graduateAndUpgrade function, there is no verification that a student's score meets or exceeds this cutoff score before including them in the graduation process:

This implementation transfers all students to Level Two without filtering out those who failed to meet the minimum score requirements.

Impact

  • Academic integrity is compromised as unqualified students can advance

  • The cutoff score mechanism becomes meaningless despite being a core feature

  • Undermines the incentive for students to achieve higher scores

  • Could lead to unprepared students in Level Two, affecting the overall educational quality

  • Breaks a fundamental protocol invariant that student advancement should be merit-based

Tools Used

  • Manual code review

  • Business logic analysis

Proof of Concept

function test_graduation_below_cutoff_score() public schoolInSession {
// Setup - add students with different scores
// Set student scores - one above cutoff, one below
vm.startPrank(alice);
vm.warp(block.timestamp + 1 weeks);
levelOneProxy.giveReview(fin, false);
vm.warp(block.timestamp + 1 weeks);
levelOneProxy.giveReview(fin, false);
vm.warp(block.timestamp + 1 weeks);
levelOneProxy.giveReview(fin, false);
vm.warp(block.timestamp + 1 weeks);
levelOneProxy.giveReview(fin, false); // 4th review
vm.stopPrank();
// Setup for graduation
levelTwoImplementation = new LevelTwo();
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
// Graduate all students regardless of scores
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(address(levelTwoImplementation), data);
// Verify both students graduated despite failing student being below cutoff
LevelTwo levelTwoProxy = LevelTwo(proxyAddress);
assertTrue(levelTwoProxy.isStudent(clara), "Passing student should graduate");
assertTrue(levelTwoProxy.isStudent(fin),
"Failing student should not graduate but was allowed to");
// Confirm the scores were transferred as-is
assertEq(levelTwoProxy.studentScore(fin), 60,
"Failing score was transferred without being filtered");
}

Recommendations

Modify the graduateAndUpgrade function to only graduate students who meet or exceed the cutoff score: drop students from the listOfStudents array who falls behind the cutOffScore .

Updates

Lead Judging Commences

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

cut-off criteria not applied

All students are graduated when the graduation function is called as the cut-off criteria is not applied.

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

cut-off criteria not applied

All students are graduated when the graduation function is called as the cut-off criteria is not applied.

Support

FAQs

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