NFTBridge
60,000 USDC
View results
Submission Details
Severity: low
Invalid

Missing storage gap in `UUPSOwnableProxied` might lead to storage collision

Summary

The UUPSOwnableProxied contract, inherited by the Bridge contract, lacks a storage gap. This violates best practices for upgradeable contracts using the UUPS pattern, creating a significant risk of storage collisions during future upgrades and potentially leading to data corruption and broken functionality.

Vulnerability Details

The UUPSOwnableProxied contract inherits from Ownable and UUPSUpgradeable, introducing its own state variable without including a storage gap:

contract UUPSOwnableProxied is Ownable, UUPSUpgradeable {
mapping(address implementation => bool initialized) _initializedImpls;
// ... other functions ...
// Missing storage gap
}

This structure limits safe upgradability, as adding new state variables in future versions could cause storage collisions with child contracts.

Impact

  • High risk of storage collisions in future upgrades

  • Potential data corruption or unexpected behavior in child contracts

  • Possible breaking of contract functionality during upgrades

  • Limited ability to add new features or state variables safely

Tools Used

Manual review

Recommendations

  1. Add a storage gap at the end of the UUPSOwnableProxied contract:

contract UUPSOwnableProxied is Ownable, UUPSUpgradeable {
mapping(address implementation => bool initialized) _initializedImpls;
// ... other functions ...
uint256[50] private __gap; // Storage gap for future upgrades
}

This __gap array reserves 50 storage slots (adjustable based on future needs), allowing safer contract upgrades by providing space for new state variables without risking collisions with existing storage layouts.

  1. Consider implementing Namespaced Storage Layout as an alternative to storage gaps. This approach provides better organization and reduces the risk of storage collisions in complex inheritance structures.

  2. Replace the standard Ownable contract with OpenZeppelin's OwnableUpgradeable:

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract UUPSOwnableProxied is OwnableUpgradeable, UUPSUpgradeable {
// ... contract code ...
}

Using OwnableUpgradeable ensures that the ownership functionality is compatible with the upgradeability pattern, further reducing the risk of storage layout issues in future upgrades.

Updates

Lead Judging Commences

n0kto Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

invalid-upgradeable-storage-gap-known-issue

Known issue: Lightchaser

Support

FAQs

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