Hawk High

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

Students who do not meet the cutoff mark still gets graduated to the second contract

Summary

The graduateAndUpgrade function in LevelOne.sol fails to enforce the protocol invariant that only students meeting or exceeding the cutOffScore—and who have received all four weekly reviews—are promoted to the next level. As a result, underperforming students can still be upgraded and counted as graduates, violating the intended access control and academic integrity of the system.

Vulnerability Details

  • Missing Score Check: There is no iteration over listOfStudents to verify that each student’s studentScore is at or above cutOffScore.

  • Missing Review Count Check: The contract does not track or enforce that each student has received exactly four reviews before allowing the upgrade. In fact, the reviewCount mapping is never incremented in giveReview, so even if checks were added, they would always fail to detect missing reviews.

  • Unconditional Upgrade: After calling _authorizeUpgrade, the function immediately transfers wages to teachers and principal without conditionally excluding failing students or preventing the upgrade if any student is below cutoff or lacks reviews.

  • Test POC: The provided Foundry test demonstrates that Harriet—whose score was reduced below the cutoff of 70 via four consecutive bad reviews—remains enrolled after graduateAndUpgrade and is counted among the students in the new LevelTwo implementation.

function test_can_student_with_poor_performance_graduate() public schoolInSession {
vm.warp(block.timestamp + 1 weeks);
vm.prank(alice);
levelOneProxy.giveReview(harriet, false);
vm.warp(block.timestamp + 1 weeks);
vm.prank(alice);
levelOneProxy.giveReview(harriet, false);
vm.warp(block.timestamp + 1 weeks);
vm.prank(alice);
levelOneProxy.giveReview(harriet, false);
vm.warp(block.timestamp + 1 weeks);
vm.prank(alice);
levelOneProxy.giveReview(harriet, false);
levelTwoImplementation = new LevelTwo();
levelTwoImplementationAddress = address(levelTwoImplementation);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
LevelTwo levelTwoProxy = LevelTwo(proxyAddress);
assert(levelOneProxy.getTotalStudents() == 6);
assert(levelTwoProxy.getTotalStudents() == 6);
console2.log(levelOneProxy.getTotalStudents()); // 6
console2.log(levelTwoProxy.getTotalStudents()); // 6 @> harriet was still upgraded
}
modifier schoolInSession() {
_teachersAdded();
_studentsEnrolled();
vm.prank(principal);
levelOneProxy.startSession(70);
_;
}
function _teachersAdded() internal {
vm.startPrank(principal);
levelOneProxy.addTeacher(alice);
levelOneProxy.addTeacher(bob);
vm.stopPrank();
}
function _studentsEnrolled() internal {
vm.startPrank(clara);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(dan);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(eli);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(fin);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(grey);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(harriet);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
}

Ran 9 tests for test/LeveOnelAndGraduateTest.t.sol:LevelOneAndGraduateTest
[PASS] test_can_student_with_poor_performance_graduate() (gas: 1474921)
Logs:
6
6

Impact

  • Academic Integrity Breach: Students who do not meet the minimum performance standards can bypass the cutoff and advance, undermining the credibility of the grading system.

  • Protocol Violation: The protocol invariant (“Any student who doesn't meet the cutOffScore should not be upgraded”) is broken, potentially leading to disputes or financial loss if only graduates receive certain benefits.

Tools Used

  • Foundry

  • Manual review

Recommendations

Enforce cutoff score before graduating students

Updates

Lead Judging Commences

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

Give us feedback!