Storage Collision
Critical vulnerability in proxy contracts where proxy and implementation use the same storage slot for different variables, causing state corruption.
Storage collision is a critical vulnerability in upgradeable smart contracts that occurs when a proxy and its implementation contract inadvertently use the same storage slot for different state variables. Because delegatecall executes implementation code using the proxy's storage, misaligned storage layouts cause variables to overwrite each other—potentially corrupting critical state, bricking contracts, or enabling complete protocol takeover. Storage collisions represent one of the most severe risks in upgradeable contract architectures.
How storage collisions occur
The EVM stores state variables in sequential 32-byte slots. When a proxy uses delegatecall to an implementation, both contracts share the same storage space:
1// Proxy contract2contract Proxy {3 address public implementation; // Slot 04 address public admin; // Slot 15}67// Implementation contract8contract ImplementationV1 {9 uint256 public totalSupply; // Slot 0 - COLLISION!10 mapping(address => uint256) public balances; // Slot 1 - COLLISION!11}
When the implementation writes to totalSupply, it actually overwrites the proxy's implementation address. This can:
- Redirect all future calls to an arbitrary address
- Brick the contract by pointing to invalid code
- Enable attackers to inject malicious implementation addresses
Real-world collision scenarios
Upgrade-induced collision
A common scenario occurs during upgrades when V2 introduces new variables:
1// V1 Implementation (working correctly)2contract V1 {3 uint256 public value; // Slot 04 address public owner; // Slot 15}67// V2 Implementation (introduces collision)8contract V2 {9 address public newAdmin; // Slot 0 - interprets value as address!10 uint256 public value; // Slot 1 - reads owner as uint256!11 address public owner; // Slot 212}
After upgrading, V2 misinterprets V1's data: value (a uint256) is read as newAdmin (an address), causing unpredictable behavior.
Proxy admin collision
If the proxy stores admin variables in low slots:
1contract Proxy {2 address implementation; // Slot 03 address admin; // Slot 14 bool initialized; // Slot 25}67contract Implementation {8 uint256 balance; // Slot 0 - overwrites implementation!9 uint256 totalSupply; // Slot 1 - overwrites admin!10}
A simple balance = 0 in the implementation could zero out the proxy's implementation address, bricking the entire contract.
Prevention: Unstructured storage (EIP-1967)
Modern proxy standards prevent collisions by storing administrative variables in pseudo-random slots derived from hashes:
1// EIP-1967 standard slots2bytes32 constant IMPLEMENTATION_SLOT =3 bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);4// = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc56bytes32 constant ADMIN_SLOT =7 bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1);89function _getImplementation() internal view returns (address impl) {10 bytes32 slot = IMPLEMENTATION_SLOT;11 assembly {12 impl := sload(slot)13 }14}
The probability of a Solidity variable naturally landing on these slots is cryptographically negligible (~1 in 2^256).
Prevention: Storage gaps
For upgradeable base contracts, reserve storage slots for future variables:
1contract BaseV1 {2 uint256 public value;3 address public owner;45 // Reserve 50 slots for future upgrades6 uint256[50] private __gap;7}89contract BaseV2 is BaseV1 {10 uint256 public newValue; // Uses slot from __gap1112 // Reduce gap by 113 uint256[49] private __gap;14}
This ensures new variables in upgrades don't shift existing storage layout.
Prevention: EIP-7201 namespaced storage
The latest standard uses struct-based namespaced storage:
1/// @custom:storage-location erc7201:myprotocol.main2struct MainStorage {3 uint256 totalSupply;4 mapping(address => uint256) balances;5}67// Storage location calculated as:8// keccak256(abi.encode(uint256(keccak256("myprotocol.main")) - 1)) & ~bytes32(uint256(0xff))
Each storage namespace gets its own isolated slot range, preventing cross-contract collisions entirely.
Detection during audits
Static analysis tools
Tools like Slither detect potential collisions:
1slither . --detect storage-layout
Foundry can inspect storage layouts:
1forge inspect ContractName storage-layout
Manual verification checklist
When auditing upgradeable contracts:
- Proxy uses EIP-1967 or similar unstructured storage
- Implementation inherits same base contracts as previous version
- New variables are added at the end, not inserted
- Storage gaps are properly maintained
- No reordering of existing variables
- Mappings and dynamic arrays don't shift
Storage collision vs type collision
Storage collision (same slot, different variables) differs from type collision (same slot, different types):
1// Type collision example2contract V1 {3 uint256 public value; // Slot 0: stored as 256-bit integer4}56contract V2 {7 address public value; // Slot 0: interpreted as 160-bit address8}
V2 reads V1's uint256 as an address, potentially extracting valid-looking addresses from arbitrary numbers—enabling attackers to craft specific values that become exploitable addresses.
Why storage collisions are critical
Storage collisions rank among the most severe smart contract vulnerabilities because they:
- Bypass all access controls - Overwriting admin variables grants unauthorized access
- Are often silent - Contracts may appear functional while corrupted
- Can be irreversible - Bricked proxies may trap funds permanently
- Affect all users simultaneously - One collision impacts every user of the proxy
- Occur during routine operations - Normal function calls can trigger corruption
Understanding storage collision is essential for anyone building or auditing upgradeable protocols. The separation of storage and logic that enables upgradeability also creates this unique attack surface requiring careful layout management across all implementation versions.
Articles Using This Term
Learn more about Storage Collision in these articles:
Related Terms
Storage Slot
32-byte memory location in EVM persistent storage where contract state variables are stored, with access costs significantly higher than memory.
Proxy Pattern
Smart contract design separating storage and logic, enabling upgrades by changing implementation while preserving state.
Delegatecall
EVM opcode that executes another contract's code in the calling contract's storage context, enabling proxy patterns and code reuse.
Diamond Standard
EIP-2535 proxy pattern allowing a single contract to delegate calls to multiple implementation contracts (facets).
Need expert guidance on Storage Collision?
Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.
Get a Quote

