Hawk High

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

Unenforced cutOffScore Threshold in Graduation Logic

Summary

The cutOffScore variable in the LevelOne contract is intended to represent the minimum score a student must achieve to graduate or qualify for rewards. While it is set during the startSession function, it is never actually used in any part of the graduation or reward logic, which in your upgraded design now resides in LevelTwo::graduate. As a result, all students—regardless of performance—are allowed to graduate, and the intended score-based filtering is silently bypassed.


Vulnerability Details

// In LevelOne:
function startSession(uint256 _cutOffScore) public onlyPrincipal notYetInSession {
sessionEnd = block.timestamp + 4 weeks;
inSession = true;
cutOffScore = _cutOffScore;
emit SchoolInSession(block.timestamp, sessionEnd);
}
// @audit-issue cutOffScore is never used to enforce graduation conditions
// @> No logic in LevelTwo::graduate() checks if studentScore >= cutOffScore
// In LevelTwo:
function graduate() public reinitializer(2) {
// @> Missing: should filter students by studentScore >= cutOffScore
}

Issue Explanation

  1. Unused Threshold
    The cutOffScore set in LevelOne is never read or enforced in the actual graduation function LevelTwo::graduate().

  2. Bypassed Academic Requirements
    Without checking studentScore against cutOffScore, students with failing performance still graduate.

  3. Misleading Design
    Stakeholders expect a score threshold to gate graduation, but the contract logic does not implement it, creating a deceptive interface.


Impact

  • Business Logic Flaw: Students who did not meet minimum performance requirements are still graduated.

  • Loss of Intended Incentive: Reviews and performance tracking have no real consequence.

  • User Confusion: Users and auditors assume the threshold is enforced, but it is not.


Tools Used

  • Manual Code Review


Recommendations

Option A – Enforce cutOffScore in LevelTwo::graduate()

Add a check in the graduate() function to only graduate and distribute rewards to students whose score meets or exceeds the threshold:

function graduate() public reinitializer(2) onlyPrincipal {
uint256 totalTeachers = listOfTeachers.length;
// Prepare payout values as needed...
// Example: uint256 payPerTeacher = (bursary * TEACHER_WAGE_L2) / PRECISION;
// uint256 principalPay = (bursary * PRINCIPAL_WAGE_L2) / PRECISION;
for (uint256 i = 0; i < listOfStudents.length; i++) {
address student = listOfStudents[i];
// @fix Only graduate students meeting the cutOffScore
if (studentScore[student] >= cutOffScore) {
// Perform graduation logic for this student:
// e.g., call upgrade, record event, etc.
}
}
// Optionally distribute bursary among qualified students and principal, then reset
bursary = 0;
inSession = false;
}

Option B – Enforce in LevelOne::graduateAndUpgrade()

If you still use LevelOne::graduateAndUpgrade for the actual payout, add the same filtering there:

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
// ... existing setup ...
for (uint256 n = 0; n < listOfStudents.length; n++) {
address student = listOfStudents[n];
if (studentScore[student] >= cutOffScore) {
// distribute to corresponding teachers/principal
}
}
bursary = 0;
}

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.

Support

FAQs

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