Account Index Bounds
Detects account array access without bounds validation, a vulnerability that appears in 30% of recent Solana audit findings.
Account Index Bounds
Overview
Remediation Guide: How to Fix Account Index Bounds
The account index bounds detector identifies Solana programs that access account arrays using an index without first validating that the index is within the array bounds. This is one of the most frequently reported vulnerabilities in Solana program audits, appearing in approximately 30% of recent findings.
In native Solana programs, accounts are passed as a slice &[AccountInfo] and accessed by index. If the program reads a user-supplied index from instruction data and uses it directly (e.g., accounts[user_index]), an out-of-bounds index causes a runtime panic. The detector tracks variable indices, constant indices, and complex expressions used to access account properties (data, lamports, owner, key).
Why This Is an Issue
An attacker can trigger a runtime panic by providing an account index that exceeds the array length. This enables denial of service (crashing the program), and in more subtle cases, can cause account confusion where the wrong account is accessed due to an off-by-one error. If the index is derived from instruction data without bounds checking, the attacker has full control over which account is accessed.
How to Resolve
pub fn process(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let target_idx = instruction_data[0] as usize;
// Validate bounds before access
if target_idx >= accounts.len() {
return Err(ProgramError::NotEnoughAccountKeys);
}
let target = &accounts[target_idx];
Ok(())
}
Examples
Vulnerable Code
pub fn process(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let idx = instruction_data[0] as usize;
// No bounds check -- panics if idx >= accounts.len()
let account = &accounts[idx];
let owner = account.owner;
Ok(())
}
Fixed Code
pub fn process(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let idx = instruction_data[0] as usize;
let account = accounts.get(idx)
.ok_or(ProgramError::NotEnoughAccountKeys)?;
let owner = account.owner;
Ok(())
}
Sample Sigvex Output
[HIGH] Account Array Access Without Bounds Validation
Location: process (block 0, stmt 1)
Description: The function accesses account[v5] via AccountData without
verifying that the index is within bounds.
CWE: CWE-129 (Improper Validation of Array Index)
Detection Methodology
- Index tracking: The detector tracks all variables used as indices when accessing account properties (data, lamports, owner, key).
- Bounds check identification: It searches for conditional comparisons of the form
index < maxormax > indexthat validate the index variable before access. - Constant index heuristic: Small constant indices (0-5) are considered likely safe for typical programs. Constant indices above 5 are flagged as potentially unsafe.
- Access type coverage: The detector covers all account property access types:
AccountData,AccountLamports,AccountOwner, andAccountKey.
Limitations
False positives: Programs with small, fixed account layouts may use constant indices that are always valid but get flagged if the index exceeds the small-constant threshold. Anchor programs using #[derive(Accounts)] receive reduced confidence because Anchor validates account count automatically. False negatives: Bounds checks performed in separate functions or through complex control flow may not be detected.
Related Detectors
- Account Iterator Bounds — detects unsafe iteration over account arrays
- Account List Size — detects missing upfront account count validation