Hawk High

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

LevelTwo lacks a reinitializer() to safely finalize the upgrade process

Summary

The LevelTwo contract does not define any meaningful initialization or reinitialization logic, despite being a replacement implementation for LevelOne in a UUPS upgradeable system. It uses a reinitializer(2) decorator on an empty and publicly callable graduate() function, which does nothing and can be called by anyone, potentially locking version 2 initialization permanently.

Vulnerability Details

In upgradeable contracts using OpenZeppelin’s UUPS pattern:

  • The original contract (LevelOne) uses initializer() during deployment via proxy.

  • Any upgraded version (LevelTwo) must define its own reinitializer(x) function to safely initialize new variables or verify existing state.

However, in LevelTwo:

  • There is no initializeV2() or equivalent reinitializer function.

  • The only function marked reinitializer(2) is an empty and unprotected graduate() function:

    function graduate() public reinitializer(2) {}
  • If this function is called once (by anyone), it will lock version 2 initialization forever, preventing proper setup later.

This makes it impossible to safely:

  • Set new state variables (principal, usdc, etc.)

  • Perform security checks on upgrade

  • Ensure upgrade flow completes as intended

Impact

  • Upgrade will appear successful, but critical variables may remain unset

  • All future upgrade logic relying on version reinitializer(2) will revert

  • Contract logic may break or revert silently due to uninitialized state

  • Introduces undefined behavior and major upgrade risks

Tools Used

Recommendations

Remove the placeholder graduate() function or move real logic into a properly secured and descriptive initializer:

function initializeV2(address _usdc, address _principal) public reinitializer(2) {
require(_usdc != address(0), "Invalid USDC");
require(_principal != address(0), "Invalid principal");
usdc = IERC20(_usdc);
principal = _principal;
}

Ensure any new logic in the upgrade path is protected with onlyPrincipal where appropriate.

Updates

Lead Judging Commences

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

failed upgrade

The system doesn't implement UUPS properly.

Support

FAQs

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

Give us feedback!