Account Iterator Bounds
Detects unsafe iteration over account arrays without bounds validation, which can lead to out-of-bounds panics or buffer overflows.
Account Iterator Bounds
Overview
Remediation Guide: How to Fix Account Iterator Bounds
The account iterator bounds detector identifies Solana programs that access elements of account arrays (or slices passed as function parameters) without verifying that the array contains enough elements. This covers sequential access patterns where multiple accounts are read from an array by index or through pointer arithmetic without a preceding length check.
Unlike the account index bounds detector which focuses on individual index validation, this detector looks at array-level access patterns: loading values from parameter-derived pointers, iterating over arrays via computed addresses, and accessing array elements without a dominating bounds check in the control flow graph.
Why This Is an Issue
An attacker who controls which accounts are included in a transaction can provide fewer accounts than the program expects. Sequential access to accounts[0], accounts[1], accounts[2] without a length check will panic on the first access that exceeds the actual array length. This enables denial of service and can waste compute units. In the worst case, an out-of-bounds read may access adjacent memory, leading to data leakage or confused program logic.
How to Resolve
pub fn process(accounts: &[AccountInfo]) -> ProgramResult {
// Validate array length upfront
if accounts.len() < 3 {
return Err(ProgramError::NotEnoughAccountKeys);
}
let payer = &accounts[0];
let vault = &accounts[1];
let authority = &accounts[2];
// Safe: all indices validated
Ok(())
}
Examples
Vulnerable Code
pub fn process(accounts: &[AccountInfo]) -> ProgramResult {
// No length check -- panics if fewer than 3 accounts
let payer = &accounts[0];
let vault = &accounts[1];
let authority = &accounts[2];
Ok(())
}
Fixed Code
pub fn process(accounts: &[AccountInfo]) -> ProgramResult {
if accounts.len() < 3 {
return Err(ProgramError::NotEnoughAccountKeys);
}
let payer = &accounts[0];
let vault = &accounts[1];
let authority = &accounts[2];
Ok(())
}
Sample Sigvex Output
[HIGH] Unsafe Account Array Access at Index param0
Location: process (block 0, stmt 0)
Description: Variable v1000 (likely an account array) is accessed
without prior bounds validation. An attacker can crash the program
by providing fewer accounts than required.
CWE: CWE-125 (Out-of-bounds Read)
Detection Methodology
- Array variable identification: The detector identifies variables that represent array or slice types, including function parameters (which typically include the accounts array) and variables assigned from array-like operations.
- Bounds check detection: It searches for expressions that compare array variables against constants or lengths, both in assignment statements and branch terminators.
- Array access detection: Load operations that reference identified array variables are recorded as array accesses.
- Protection analysis: For each access, the detector checks whether a bounds check exists at an earlier program point in the same block or a predecessor block.
Limitations
False positives: The detector uses a simplified dominance analysis rather than a full CFG dominator tree, which may miss bounds checks in complex control flow. Anchor programs receive reduced confidence because #[derive(Accounts)] validates account count. False negatives: Bounds checks in called functions or checks using indirect comparisons may not be detected.
Related Detectors
- Account Index Bounds — detects individual index access without validation
- Account List Size — detects missing upfront count validation for fixed account layouts