Skip to content
Last updated: February 06, 2026

SCWE-099: Storage Layout Collision on Upgrade

Stable Version v1.0

This content is in the version-(v1.0) and still under active development, so it is subject to change any time (e.g. structure, IDs, content, URLs, etc.).

Send Feedback

Relationships

Description

Upgradeable contracts rely on stable storage slots. Reordering, removing, or inserting state variables (or changing inheritance order) between versions causes storage collisions when the proxy reuses the same slots, corrupting balances, roles, or configuration.

Remediation

  • Freeze variable ordering; only append new variables.
  • Reserve gaps (uint256[50] private __gap;) to allow future expansion.
  • Use automated storage layout diffing and follow upgrade-safe patterns (e.g., OZ Upgradeable tooling).

Examples

Vulnerable

pragma solidity ^0.8.0;

contract V1 {
    address public owner;   // slot 0
    uint256 public balance; // slot 1
}

contract V2 is V1 {
    uint256 public balance; // reuses slot 1, corrupts state
    address public treasury;
}

Fixed

pragma solidity ^0.8.0;

contract V1 {
    address public owner;   // slot 0
    uint256 public balance; // slot 1
    uint256[48] private __gap;
}

contract V2 is V1 {
    uint256 public treasuryFee; // slot 2 (after gap)
}