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.
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).
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.
Financial Discrepancy: bursary underrepresents the actual USDC, leading to failed wage transfers.
Upgrade Failure: Prevents the upgrade to LevelTwo, stalling the system.
Validate and convert schoolFees to 18-decimal wei in initialize. Here’s the diff:
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.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.