Account Iterator Bounds Remediation
How to fix unsafe iteration over account arrays without bounds validation.
Account Iterator Bounds Remediation
Overview
Related Detector: Account Iterator Bounds
Programs that sequentially access account array elements without verifying the array length will panic when fewer accounts are provided than expected. The fix is to validate the array length before accessing any elements, or to use safe iteration patterns that handle short arrays gracefully.
Recommended Fix
Before (Vulnerable)
pub fn process_multi(accounts: &[AccountInfo]) -> ProgramResult {
let source = &accounts[0];
let dest = &accounts[1];
let authority = &accounts[2];
let fee_receiver = &accounts[3];
// Panics if fewer than 4 accounts provided
Ok(())
}
After (Fixed)
pub fn process_multi(accounts: &[AccountInfo]) -> ProgramResult {
const REQUIRED: usize = 4;
if accounts.len() < REQUIRED {
return Err(ProgramError::NotEnoughAccountKeys);
}
let source = &accounts[0];
let dest = &accounts[1];
let authority = &accounts[2];
let fee_receiver = &accounts[3];
Ok(())
}
Alternative Mitigations
Use next_account_info for safe sequential consumption:
let iter = &mut accounts.iter();
let source = next_account_info(iter)?;
let dest = next_account_info(iter)?;
let authority = next_account_info(iter)?;
// Automatically returns NotEnoughAccountKeys on underflow
Use Anchor’s #[derive(Accounts)] to declare the exact account layout:
#[derive(Accounts)]
pub struct MultiTransfer<'info> {
#[account(mut)]
pub source: Account<'info, TokenAccount>,
#[account(mut)]
pub dest: Account<'info, TokenAccount>,
pub authority: Signer<'info>,
pub fee_receiver: AccountInfo<'info>,
}
Use .get() with error handling when accessing individual elements:
let source = accounts.get(0).ok_or(ProgramError::NotEnoughAccountKeys)?;
Common Mistakes
Checking the length for the first access but forgetting subsequent ones. A single accounts.len() >= N check at the top of the function, where N is the maximum index + 1, is the cleanest pattern.
Using for account in accounts without checking the minimum count. Iterating over all provided accounts is safe from a bounds perspective, but if the loop body assumes a minimum number of iterations, fewer accounts can cause logic errors.
Mixing index access with next_account_info. Combining both patterns makes it difficult to reason about which accounts have been consumed and can lead to off-by-one errors.