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 3 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.