Hawk High

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

LevelOne contract missing initializer protection enables critical vulnerability

Summary

The LevelOne smart contract contains a critical vulnerability in its UUPS implementation. By missing the essential _disableInitializers() function in its constructor, the contract allows any external address to directly initialize the implementation contract. This creates a dangerous backdoor that enables an attacker to completely destroy the contract system by delegating to malicious code containing a self-destruct instruction.

Vulnerability Details

Let me walk you through a step-by-step demonstration of how this attack unfolds.

Step 1: Implementation Contract Initialization Attack

When the LevelOne implementation is deployed, it exists as a standalone contract. Without protection, an attacker can directly initialize it and set themselves as principal.

Step 2: Creating the Malicious Self-Destruct Contract

The attacker deploys a contract designed to destroy the implementation:

// MaliciousPayload.sol
contract MaliciousPayload {
// This function will be called via delegatecall
function destroyImplementation() external {
// When called through delegatecall, this destroys the implementation contract
selfdestruct(payable(msg.sender));
}
}

Step 3: Call upgradeToAndCall function

The attacker calls upgradeToAndCall directly on the implementation contract, passing the address of the malicious self-destruct contract. Since the attacker is recognized as the principal in the implementation's storage, the authorization check passes. The function delegates to the malicious contract, which executes selfdestruct() in the implementation's context.

Impact

The direct call to the implementation triggers a delegatecall to the malicious contract, which executes selfdestruct() and destroys the implementation's bytecode. This permanently disables the implementation contract, making all proxy functions that delegate to it inoperable.

Tools Used

Manual review

Recommendations

Add constructor with _disableInitializers() function to implementation contract.

Updates

Lead Judging Commences

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