Skip to main content
Sigvex

Storage Layout Versioning Remediation

How to keep upgradeable proxies safe by preserving storage layout: append-only variables, storage gaps, and namespaced slots.

Storage Layout Versioning Remediation

Overview

Related Detector: Storage Layout Versioning

An upgradeable proxy keeps its storage while swapping implementation code. If a new implementation reorders variables, removes one, inserts one before existing ones, or changes a type, every subsequent slot shifts — and the new code reads old data from the wrong place. The remediation is to treat storage layout as an append-only contract between versions.

Before (Vulnerable — inserting a variable shifts all later slots)

// V1
contract VaultV1 { address owner; uint256 total; }

// V2 inserts `paused` before `total` — `total` now reads what `owner` held.
contract VaultV2 { address owner; bool paused; uint256 total; }

After (Fixed — append only, and reserve a gap)

contract VaultV2 {
    address owner;
    uint256 total;
    bool paused;          // NEW variables are always appended at the end

    uint256[49] private __gap;   // reserve slots so future appends don't collide
}

Prefer namespaced storage (ERC-7201) for new upgradeable contracts, which isolates each module’s variables under a hashed slot and removes ordering fragility entirely. Always run a storage-layout diff between versions before upgrading.

Common Mistakes

  • Inserting or reordering variables instead of appending, silently corrupting every later slot.
  • Changing a variable’s type (e.g. uint128 to uint256) so packed neighbours shift.
  • Removing a __gap or shrinking it incorrectly when adding variables, reintroducing collisions.

References