Skip to content
Security
Skill

/storage-layout

Detect storage-layout issues in upgradeable contracts — slot collisions, slot reuse, packing changes, missing gap. Activate when reviewing UUPS/Transparent proxies, OZ Upgradeable contracts, diamonds (EIP-2535), libraries with structs, or any contract using assembly to read

From plugin
rugproof
1052 skills23 agents45 commands4 hooks

Claude Code

$ npx -y skills add omermaksutii/RugProof --skill storage-layout --agent claude-code

SKILL.md

storage-layout.SKILL.md
name: storage-layout
description: Detect storage-layout issues in upgradeable contracts — slot collisions, slot reuse, packing changes, missing gap. Activate when reviewing UUPS/Transparent proxies, OZ Upgradeable contracts, diamonds (EIP-2535), libraries with structs, or any contract using assembly to read storage slots.

Storage layout detection

When this applies

  • UUPS / Transparent proxy upgrades
  • OpenZeppelin `*Upgradeable` contracts
  • EIP-2535 Diamonds with shared storage
  • Libraries that read storage via assembly
  • Any change that modifies inheritance order or struct layout in an upgradeable contract
  • Initializers that depend on storage being zero

Detection patterns

Missing __gap (HIGH)

contract BaseUpgradeable {
    uint256 public foo;
    // no uint256[50] __gap;   ← can't append fields to derived contracts safely
}

OZ convention: each base contract reserves `__gap` for future fields.

Slot collision between proxy and implementation (CRITICAL)

Implementation defines `address public owner` in slot 0; proxy uses slot 0 for its admin. Hello, hijacked proxy. Use EIP-1967 slots (`bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)`).

Inheritance reorder breaks layout (HIGH)

// V1: contract X is A, B, C
// V2: contract X is A, C, B   ← B's vars now at C's old slots

Even one append to a parent breaks all descendants.

Struct field reorder/insert (HIGH)

Solidity packs adjacent same-bit-width fields. Inserting a `bool` between two `uint256` adds a slot. Verify with `forge inspect <Contract> storage`.

Type widening (HIGH)

`uint8` → `uint256` changes packing.

Library uses fixed assembly slot (MEDIUM-HIGH)

assembly { sstore(0x0, value) }   // ← collides with the consumer's slot 0

Use namespaced storage (`keccak256("myapp.storage.foo")`).

Diamond storage namespace collision (HIGH)

Two facets using the same `bytes32 STORAGE_POSITION`. Always derive from a unique namespace string.

ERC-7201 namespaced storage missing on new code (MEDIUM)

Modern best-practice: use `@custom:storage-location erc7201:my.namespace`.

Severity rubric

| Pattern | Severity | |---|---| | Proxy/impl slot 0 collision | **Critical** | | Slot reuse after upgrade (data corruption) | **Critical** | | Struct reorder in upgrade | **High** | | Inheritance reorder | **High** | | Missing `__gap` in upgradeable base | **High** | | Diamond storage collision | **High** | | Library writing to fixed low slots | **High** | | ERC-7201 missing on new namespaced module | **Medium** | | Variable rename only (same slot) | **Info** |

Remediation patterns

  • Run `forge inspect <Contract> storageLayout` for V1 and V2; diff JSON. Any non-append change = abort.
  • OpenZeppelin Upgrades Plugin: `validateUpgrade()` catches most layout breaks at build time.
  • Each upgradeable base contract reserves `uint256[N] private __gap` at the end (size by convention).
  • Use EIP-1967 / EIP-7201 for namespaced storage in libraries and diamonds.
  • Never modify or remove existing storage slots — only append.

False-positive notes

  • Adding a *constant* or `immutable` variable doesn't change storage layout (lives in bytecode, not storage).
  • Pure function additions don't affect layout.
  • Internal helper changes within a function don't affect layout.

Related

  • [[initialization]] — re-init after upgrade
  • [[delegatecall-risks]] — proxy mechanics
  • [[upgrade-safety]] (command/skill bridge)
Read more
@omermaksutii
Ships withrugproof

Rugproof your code before someone else does. 🌐 Live site: omermaksutii.github.io/RugProof 📦 Latest: v1.0.0 — 45 commands · 23 agents · 45 skills · 13 MCP servers · tested, offline-first, with rule packs, a benchmark, non-EVM coverage, and post-deploy

1052 skills23 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
10
Star history of omermaksutii/RugProof on GitHub, a chart by star-history.com

Other skills on rugproof.

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

nemoclaw13d23k
@nvidia@nvidiaInstall Skill

Questions about storage-layout.

Which coding agents can use storage-layout?
storage-layout installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.