The LevelOne contract inherits from UUPSUpgradeable but does not properly protect its initialize() function. Although the initializer modifier is used, it only prevents the function from being called more than once on the proxy. If someone deploys the LevelOne implementation contract directly (not via proxy), they can call initialize() and become the principal, which enables them to call upgradeToAndCall() and take full control of the contract logic.
An attacker could deploy the implementation contract, call initialize() to set themselves as principal, and then perform a malicious upgrade using upgradeToAndCall(). This could lead to full contract takeover or destruction of logic.
Add an access control check in the initialize() function to ensure it cannot be called arbitrarily when deployed as an implementation contract. One pattern is to use an initialized flag or enforce ownership via constructor if not using proxy directly.
Alternatively, avoid deploying the logic contract on-chain directly unless it’s required, or add an onlyInitializing modifier inside a constructor to prevent misuse.
Manual Review
Slither
The system can be re-initialized by an attacker and its integrity tampered with due to lack of `disableInitializer()`
The system can be re-initialized by an attacker and its integrity tampered with due to lack of `disableInitializer()`
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.