Hawk High

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

For the sake of this project, assume USDC has 18 decimals

Summary

The initialize function accepts schoolFees without validating it is provided in 18-decimal wei, as required by the USDC invariant. This mismatch propagates to enroll, causing bursary to misrepresent the actual USDC balance, risking failed transfers and upgrade issues.

Vulnerability Details

  • Root Cause: The initialize function sets schoolFees = _schoolFees without ensuring _schoolFees is in 18-decimal wei (e.g., 100 USDC = 100 * 10^18). If a caller provides 100e6 (6-decimal USDC), schoolFees is misinterpreted.

  • Attack Path: In enroll, usdc.safeTransferFrom transfers the correct 18-decimal amount, but bursary += schoolFees adds the misaligned value. In graduateAndUpgrade, payPerTeacher and principalPay use the incorrect bursary, leading to insufficient funds for transfers.

  • Affected Component: Initialization and financial tracking (schoolFees, bursary).

Proof of Concept

The following steps demonstrate the vulnerability:

  • Step 1: Initialize the contract with schoolFees = 100e6 (intended as 100 USDC but provided as 6-decimal units).

  • Step 2: Enroll 2 students, each transferring 100e18 USDC (correct 18-decimal amount). bursary becomes 200e6 (misaligned), while the actual balance is 200e18.

  • Step 3: Add 2 teachers and start a session with startSession(70).

  • Step 4: After 5 weeks, call graduateAndUpgrade(address(new LevelTwo()), "").

  • Expected Result: Transfers succeed, with bursary reflecting 200e18.

  • Actual Result: payPerTeacher = (200e6 * 35) / 100 = 70e6 per teacher, totaling 140e6 + 10e6 (principal) = 150e6, but the balance is 200e18. The transfer of 70e6 (interpreted as 70e6 wei, not 70 USDC) fails due to a mismatch.

Impact

  • Financial Discrepancy: bursary underrepresents the actual USDC, leading to failed wage transfers.

  • Upgrade Failure: Prevents the upgrade to LevelTwo, stalling the system.

Recommendations

Validate and convert schoolFees to 18-decimal wei in initialize. Here’s the diff:

function initialize(address _principal, uint256 _schoolFees, address _usdcAddress) public initializer {
if (_principal == address(0)) {
revert HH__ZeroAddress();
}
if (_schoolFees == 0) {
revert HH__ZeroValue();
}
if (_usdcAddress == address(0)) {
revert HH__ZeroAddress();
}
principal = _principal;
- schoolFees = _schoolFees;
+ schoolFees = _schoolFees * 10**12; // Convert from 6-decimal to 18-decimal (assuming 6-decimal input)
usdc = IERC20(_usdcAddress);
__UUPSUpgradeable_init();
}

Note: Adjust the multiplier (1012) based on the expected input decimal (e.g., 1018 if raw wei is expected). Add documentation to clarify expected units.

Updates

Lead Judging Commences

yeahchibyke Lead Judge 20 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
yeahchibyke Lead Judge 20 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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