Uninitialized Storage
Detects storage variables and struct pointers used before initialization, where default zero values may cause unexpected behavior.
Uninitialized Storage
Overview
The uninitialized storage detector identifies storage variables that are read before being written, and struct pointers declared as local storage variables that default to slot 0. In older Solidity versions (< 0.5.0), a local variable declared as storage without explicit assignment pointed to storage slot 0, allowing an attacker to overwrite critical state by manipulating what they thought was a local variable.
In current Solidity, the compiler prevents uninitialized storage pointers. However, uninitialized state variables (which default to zero) remain a risk when contract logic assumes a non-zero initial value.
Why This Is an Issue
The Parity wallet hack class (November 2017) demonstrated how uninitialized storage pointers could corrupt ownership state. While the specific pointer vulnerability is fixed in modern Solidity, uninitialized state variables continue to cause issues: a governance contract that reads an uninitialized quorum variable (default 0) may allow proposals to pass with zero votes.
How to Resolve
// Before: Vulnerable — quorum defaults to 0, allowing instant proposal passage
contract VulnerableGov {
uint256 public quorum; // Uninitialized — defaults to 0
function execute(uint256 proposalId) external {
require(votes[proposalId] >= quorum, "Not enough votes"); // Always passes!
}
}
// After: Fixed — initialize in constructor
contract SafeGov {
uint256 public quorum;
constructor(uint256 _quorum) {
require(_quorum > 0, "Quorum must be positive");
quorum = _quorum;
}
}
Detection Methodology
- SLOAD-before-SSTORE tracking: For each storage slot, tracks whether the first access is a read (
SLOAD) or a write (SSTORE). Slots read before any write in the constructor or initialization path are flagged. - Storage pointer detection: In bytecode compiled with Solidity < 0.5.0, identifies local variables that reference storage slot 0 due to implicit initialization.
- Zero-value assumption check: Flags storage reads where the result is used in comparisons, divisions, or access control checks without a preceding write.
Limitations
False positives: Variables intentionally initialized to zero (e.g., counters) may be flagged. False negatives: Variables initialized in one function and read in another may not be connected without cross-function analysis.
Related Detectors
- Access Control — detects missing authorization
- UUPS Initialization — detects uninitialized proxy implementations