This report details a significant design flaw in the LevelOne.sol contract system. The principal has the ability to directly call the upgradeToAndCall function on the proxy contract, thereby upgrading the system to LevelTwo.sol (or any other target implementation) without executing the financial settlement logic (payouts to teachers and principal) contained within the graduateAndUpgrade function. This bypass capability undermines the intended coupling of end-of-session payouts with the upgrade process. This issue is critically exacerbated if the graduateAndUpgrade function itself is susceptible to a Denial of Service (DoS), as it would leave the direct upgrade path as the only viable option for the principal, forcing a scenario where teachers are not paid as per the LevelOne.sol contract's design.
The LevelOne.sol contract utilizes the UUPS upgrade pattern. The _authorizeUpgrade function, which gates the upgrade process, is restricted by an onlyPrincipal modifier:
The contract provides a graduateAndUpgrade function intended to handle end-of-session payouts and then call _authorizeUpgrade. However, the UUPSUpgradeable contract (inherited by LevelOne.sol) also exposes an external upgradeToAndCall(address newImplementation, bytes calldata data) function.
The principal can call upgradeToAndCall directly on the proxy contract. This call will:
Be delegated to the current LevelOne.sol implementation.
Internally invoke _authorizeUpgrade(newImplementation).
Since the caller (the principal) satisfies the onlyPrincipal modifier, the authorization will succeed, and the proxy will be upgraded to newImplementation.
This direct invocation of upgradeToAndCall completely bypasses the payout logic within the graduateAndUpgrade function. If graduateAndUpgrade is DoS'd (e.g., due to a blacklisted USDC recipient for teacher payouts), the principal might be compelled to use this direct upgrade path, leading to a situation where teachers are not paid their share of the bursary from LevelOne.sol.
Setup:
A session in LevelOne.sol concludes.
The bursary contains funds for teacher and principal payouts.
(Optional, but exacerbating) The graduateAndUpgrade function is unusable due to a DoS condition (e.g., a blacklisted teacher address).
Execution:
The principal decides to upgrade the contract to LevelTwo.sol.
Instead of calling graduateAndUpgrade, the principal directly calls upgradeToAndCall(addressOfLevelTwo, initializationData) on the proxy contract.
Outcome:
The _authorizeUpgrade check within the upgradeToAndCall flow passes because the caller is the principal.
The proxy contract's implementation is successfully changed to LevelTwo.sol.
The payout logic within graduateAndUpgrade (transferring USDC to teachers and the principal from LevelOne.sol's bursary) is never executed.
Teachers are not paid their due from LevelOne.sol. The bursary funds remain in the proxy's storage, potentially unmanaged or inaccessible by the old logic.
Circumvention of Financial Obligations: The principal can upgrade the system without fulfilling the financial settlements promised to teachers within the LevelOne.sol contract's lifecycle.
Centralization of Power: It grants the principal excessive control, allowing them to prioritize system upgrades over agreed-upon financial distributions, especially if the intended combined function (graduateAndUpgrade) is blocked.
Broken Trust and Incentives: Teachers participate with the expectation of payment. If this can be bypassed, it erodes trust in the system and disincentivizes participation.
Funds Potentially Stranded: If the contract is upgraded without payouts, the bursary funds managed by LevelOne.sol's logic might become difficult to distribute correctly unless LevelTwo.sol is specifically designed to handle this leftover state, which is not apparent from the provided LevelTwo.sol code.
Manual Code Review
The system design should ensure that critical financial settlements are robustly tied to the upgrade process or that the principal cannot easily (or is not incentivized to) bypass them.
Make graduateAndUpgrade Robust: The primary recommendation is to fix the DoS vulnerabilities within graduateAndUpgrade (e.g., using try/catch for USDC transfers to blacklisted addresses, correcting payout calculations). If graduateAndUpgrade works reliably, the principal has less incentive to bypass it.
Consider Design Changes for Stronger Coupling (Complex):
One advanced and more complex approach could involve a two-step upgrade process where graduateAndUpgrade sets a flag or a specific authorized new implementation address, and _authorizeUpgrade checks this flag/address. This would make graduateAndUpgrade a mandatory prerequisite. However, this deviates from standard UUPS simplicity and adds complexity.
Alternatively, ensure that LevelTwo.sol (and future versions) has a clear, audited mechanism to process any pending payouts from the previous version's bursary if an upgrade occurs before full settlement. This would require careful state management and potentially access to previous state variables or a migration path.
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.