Hawk High

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

Unprotected Initialization

Description: The logic of LevelOne::initialize function is marked public initializer, but there is no call to _disableInitializers() in the implementation's constructor. That means anyone can call initialize on the logic contract and become principal, set arbitrary schoolFees or usdc, and then drain or destroy funds.

Impact: This runs initialize() in the implementation contract's own storage, sets '_initialized = 1' in the logic contract, and potentially sets 'owner = attacker'. An attacker can hijack the contract by re-initializing the logic implementation, minting themselves ownership and privileges, and either steal USDC or upgrade to malicious code. Also, the attacker can interfere with reinitializer(x) logic.

Proof of Concept: Include the following test in the LevelOneAndGraduateTest.t.sol file:

function testReinitializeLogic() public {
// Initialize the proxy with the first implementation
deployBot = new DeployLevelOne();
proxyAddress = deployBot.deployLevelOne();
address attacker = makeAddr("attacker");
LevelOne levelOneImplementation = new LevelOne();
// Initialize directly, not via proxy
LevelOne(address(levelOneImplementation)).initialize(attacker, schoolFees, address(usdc));
assertEq(levelOneImplementation.getPrincipal(), attacker);
}

Even if the proxy was correctly initialized first, the logic contract is now initialized with its own state (could confuse tools like Etherscan, OpenZeppelin Defender) and has its own owner (someone may accidentally interact with the wrong address).

Recommended Mitigation: In the implementation contract's constructor, call _disableInitializers() to ensure initialize cannot be called on the logic contract.

constructor() {
+ _disableInitializers();
}

This prevents anyone from initializing the logic contract itself and ensures only the proxy can be initialized.

Updates

Lead Judging Commences

yeahchibyke Lead Judge 3 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.