The LevelOne smart contract's initialize(...) function places a __UUPSUpgradeable_init() call at the end of the function, after critical state variables have already been set. This ordering introduces a subtle but significant risk in the context of upgradable contract security, particularly around proxy initialization and upgrade paths.
While the __UUPSUpgradeable_init() function itself is not currently overridden or implemented, best practices and defensive programming dictate that it should be called before any sensitive logic, to ensure the proxy's state is properly initialized before any other operations.
In UUPS (Universal Upgradeable Proxy Standard) upgradeable contracts, the __UUPSUpgradeable_init() function initializes the upgradeability mechanism via OpenZeppelin’s UUPSUpgradeable base. This method typically sets internal storage variables and includes access control logic related to upgrades.
The issue is that __UUPSUpgradeable_init() is called after the contract has already set critical parameters, which could introduce inconsistencies if the initializer modifier were removed or bypassed due to inheritance conflicts or bugs. If an attacker finds a way to re-initialize the contract (through a misconfigured proxy, for instance), calling sensitive logic before properly initializing upgradeability controls can potentially lead to a privilege escalation or denial of service.
Incorrect Initialization Sequence: If __UUPSUpgradeable_init() contains security-critical logic (such as setting upgrade permissions), invoking it after modifying storage could expose the contract to improper states.
Potential Exploitation in Edge Cases: If the initializer modifier is not correctly applied (e.g., due to complex inheritance), a malicious actor could take advantage of the incorrect order.
Reduced Auditability: Deviating from common upgradeable contract patterns makes future audits and verifications more error-prone.
While this specific instance may not be immediately exploitable, it's a ticking time bomb in complex deployments — especially as upgradeability logic gets layered in.
Foundry
Manual code review
Move the __UUPSUpgradeable_init() call to the beginning of the initialize() function to ensure the contract's upgradeable mechanism is set up before executing any state-changing logic:
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.