Hawk High

First Flight #39
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

Students Not Meeting cutOffScore Are Still Upgraded

Summary

The function graduateAndUpgrade upgrades the contract without checking whether individual students meet the cutOffScore, violating the stated invariant.

Vulnerability Details

The current implementation lacks any logic that filters or validates students based on their scores. If upgrading students is part of the upgrade process (e.g., migrating state, promoting users), this results in all students being upgraded, including those who have not met the required threshold.

This contradicts the expected invariant:

Any student who doesn't meet the cutOffScore should not be upgraded.

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
uint256 totalTeachers = listOfTeachers.length;
uint256 payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION;
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION;
//>> No check for students cutoff
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
}

Impact

  • Students who failed to meet academic requirements can still be upgraded.

  • This could lead to incorrect system states, degraded trust in progression logic, or unauthorized access to higher-level privileges.


Recommendations

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
// Create a dynamic array to track eligible students
address[] memory eligibleStudents = new address[](listOfStudents.length);
uint256 eligibleCount = 0;
// Filter students who meet the cutoff
for (uint256 i = 0; i < listOfStudents.length; i++) {
address student = listOfStudents[i];
if (studentScore[student] >= cutOffScore) {
eligibleStudents[eligibleCount] = student;
eligibleCount++;
}
}
// Overwrite the old list with only eligible students
// (This reduces gas costs by resizing only once)
listOfStudents = new address[](eligibleCount);
for (uint256 i = 0; i < eligibleCount; i++) {
listOfStudents[i] = eligibleStudents[i];
}
// Proceed with the upgrade and payments (if needed)
uint256 totalTeachers = listOfTeachers.length;
uint256 payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION;
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION;
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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