Hawk High

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

Contract upgrade and wage distribution bypass graduation criteria and timing requirements

Summary

The system allows the principal to upgrade the contract and distribute wages before students meet the required number of reviews or complete minimum enrolment duration. This undermines the system's integrity and trust model, potentially leaving students ungraded and financially disadvantaged.

Vulnerability Details

The LevelOne.sol::graduateAndUpgrade function lacks validation for key invariants: it does not check whether students have received the required number of reviews, nor does it enforce a minimum time period after enrolment before the system can be upgraded.

As a result, the principal can prematurely trigger an upgrade and release payments to teachers and themselves, bypassing the graduation requirements. This violates the logical flow of the system, where graduation should precede both contract upgrades and wage disbursements.

Relevant code:

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;
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
}

Impact

  • Impact: High – Premature upgrades and payouts can result in students not receiving their expected reviews despite having paid fees, severely eroding trust in the system and breaking the educational logic enforced by the contract.

  • Likelihood: High - The absence of critical safeguards (such as review count and time-based checks) enables both accidental misuse and deliberate exploitation of the system. Even with a trusted principal, the ease of triggering an upgrade and wage disbursement in a single call makes this vulnerability a significant risk.

Tools Used

  • Manual review of the GraduiateAndUpgrade function

  • Foundry test

Proof of Concept:

The following test demonstrates that a student can graduate without receiving any reviews, and wages are paid out nonetheless::

modifier oneTeacher() {
_oneTeachersAdded();
_studentsEnrolled();
vm.prank(principal);
levelOneProxy.startSession(70);
_;
}
function test_review_count_after_graduate() public oneTeacher {
levelTwoImplementation = new LevelTwo();
levelTwoImplementationAddress = address(levelTwoImplementation);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
assertEq(levelOneProxy.getReviewCount(clara),0);
assertEq(usdc.balanceOf(address(alice)), 105e20);
assertEq(usdc.balanceOf(address(principal)), 15e20);
}

Recommendations

  • Add a check in GraduateAndUpgrade function to ensure that each student has received the required number of reviews, i.e. 4, before allowing graduation and wage disbursement.

  • Introduce a minimum delay, i.e. 4 weeks, after student enrolment before the contract can be upgraded to ensure a fair and complete educational process.

Updates

Lead Judging Commences

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

can graduate without session end

`graduateAndUpgrade()` can be called successfully even when the school session has not ended

Support

FAQs

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