Unchecked Array Bounds
Detects array accesses without bounds validation, enabling out-of-bounds reads/writes that corrupt storage or cause unexpected reverts.
Unchecked Array Bounds
Overview
The unchecked array bounds detector identifies storage and memory array accesses where the index is derived from user input or external data without a preceding bounds check. While Solidity 0.8+ reverts on out-of-bounds access to storage arrays, dynamic memory arrays and assembly-level operations do not have this protection. Additionally, even with automatic bounds checks, relying on revert-based protection can cause denial of service.
Why This Is an Issue
Array bounds violations cause two distinct problems:
- Denial of service: If an attacker can trigger an out-of-bounds access, the transaction reverts, blocking the entire operation. In batch operations or governance execution, this can stall critical functions.
- Storage corruption (assembly): In
assemblyblocks or contracts compiled with older Solidity versions, out-of-bounds writes can corrupt adjacent storage slots, overwriting critical variables like ownership or balances.
DEX and vault contracts that use indices to reference pools or positions are particularly vulnerable. An attacker providing an invalid pool index can DoS withdrawal functions or, in older contracts, corrupt pool accounting.
How to Resolve
// Before: Index from calldata used without validation
function getPool(uint256 index) external view returns (Pool memory) {
return pools[index]; // Reverts if index >= pools.length, causing DoS
}
// After: Explicit bounds check with informative error
function getPool(uint256 index) external view returns (Pool memory) {
require(index < pools.length, "Invalid pool index");
return pools[index];
}
Examples
Vulnerable Code
contract VulnerableRegistry {
address[] public validators;
// Attacker can pass any index -- no validation
function removeValidator(uint256 index) external onlyAdmin {
// If index >= validators.length, reverts with panic
// In batch removal, one bad index blocks the entire batch
validators[index] = validators[validators.length - 1];
validators.pop();
}
}
Fixed Code
contract SafeRegistry {
address[] public validators;
function removeValidator(uint256 index) external onlyAdmin {
require(index < validators.length, "Index out of bounds");
validators[index] = validators[validators.length - 1];
validators.pop();
}
}
Sample Sigvex Output
{
"detector_id": "unchecked-array-bounds",
"severity": "high",
"confidence": 0.85,
"description": "Array access at offset 0x8e uses user-supplied index parameter without bounds validation. An out-of-range index causes a panic revert, enabling DoS of the removeValidator() function.",
"location": { "function": "removeValidator(uint256)", "offset": 142 }
}
Detection Methodology
- Index source tracking: Traces array index values back to their origin (calldata parameters, storage reads, external call returns).
- Bounds check detection: Scans for comparison operations (
LT,GT) against array length before the array access. - Assembly analysis: Checks
mload/mstore/sload/sstorein assembly blocks for unchecked offset calculations. - Confidence scoring: Higher confidence when the index originates directly from calldata; lower when derived from trusted internal state.
Limitations
- Solidity 0.8+ automatic bounds checking on storage arrays means the vulnerability manifests as DoS rather than corruption. The detector flags both.
- Cannot determine whether a revert-on-out-of-bounds is intentional design (e.g., the function is expected to revert for invalid inputs).
- Mapping accesses (which have no bounds concept) are excluded.
Related Detectors
- Controlled Array Length — unbounded array iteration
- Off By One — off-by-one errors in boundary calculations
- Array Deletion Index — unsafe array element deletion