(HIGH) Tuition fees paid by students are permanently locked within the contract.
Affected Assets
https://github.com/CodeHawks-Contests/2025-05-hawk-high/blob/main/src/LevelOne.sol#L295-L312
https://github.com/CodeHawks-Contests/2025-05-hawk-high/blob/main/src/LevelTwo.sol#L28
The school contract (LevelOne
) collects school fees in USDC from students. When the principal decides to "graduate" the school to the next level (LevelTwo
), they call a function that upgrades the contract logic to the LevelTwo
code. During this upgrade process, all the USDC held by the LevelOne
contract (which is actually held by the proxy contract) is automatically transferred to the new LevelTwo
contract's address (which is still the same proxy address, but now executing the LevelTwo
logic).
The problem is that the LevelTwo
contract code has no way to access or withdraw this USDC. The special function that is supposed to run right after the upgrade (graduate()
) is completely empty. There are no other functions in LevelTwo
that allow anyone, including the principal, to get the money out. This means all the collected school fees are permanently stuck and lost inside the contract.
Manual Review
Report generation with AI assistance
The core issue is the lack of fund management logic in the LevelTwo
contract after the upgrade.
Implement Fund Management in LevelTwo
:
Add a function to the LevelTwo
contract that allows the principal (or another authorized address) to withdraw the collected school fees (USDC). This function should likely be part of the reinitializer or a separate function callable only by the principal.
Likelihood of Exploitation: High. While not an "exploit" in the sense of malicious gain by an external attacker, the vulnerability is triggered by the intended and necessary action of upgrading the contract. The principal will eventually call graduateAndUpgrade
to move to the next phase of the project. When they do, the funds will be locked. This is a guaranteed outcome of using the contract as designed with the current code.
Funds are stuck in `LevelOne()` contract after upgrade.
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.