Hawk High

First Flight #39
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Missing call to `_disableInitializers()`

Summary

The LevelOne contract does not define the constructor, nor does it explicitly disable or protect the initialize() function in the implementation contract. This allows unauthorized actors to initialize the implementation contract directly, leading to unintended state changes and potentially causing unexpected behavior in the implementation contract.

Vulnerability Details

In upgradeable contract patterns like UUPS or Transparent Proxy, only the proxy is intended to delegate calls to the implementation contract. The implementation contract’s initialize() function replaces the constructor and is expected to be called once (via the proxy).

However, because constructors in implementation contracts are executed during deployment, a common best practice is to call _disableInitializers() in the constructor to lock down any initializer functions on the implementation contract itself.

This ensures that initialization logic cannot be executed directly on the logic contract. In the current implementation, _disableInitializers() is missing, leaving the initialize() function unprotected when called directly on the implementation contract. Since the initializer modifier only tracks state per contract instance, this leads to the implementation contract itself being mutable and exposed to front-running or accidental misuse.

Impact

  • Unintended state changes in the implementation contract storage.

  • Possibility of initialization logic being triggered outside of the proxy contract.

  • Increased attack surface if implementation contract is mistakenly assumed to be immutable.

Tools Used

  • Manual Code Review

Recommendations

Add a call to _disableInitializers() in the constructor of the implementation contract to prevent any direct use of initialize() or other initializer functions:

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

This ensures that the implementation contract cannot be initialized independently, preserving the security assumptions of the proxy-based upgradeable pattern.

Updates

Lead Judging Commences

yeahchibyke Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

contract can be re-initialized

The system can be re-initialized by an attacker and its integrity tampered with due to lack of `disableInitializer()`

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!