Account List Size
Detects missing account list size validation for programs that expect a fixed number of accounts.
Account List Size
Overview
Remediation Guide: How to Fix Account List Size
The account list size detector identifies Solana programs that access multiple accounts at fixed constant indices (e.g., accounts[0], accounts[1], accounts[2]) without validating the total number of accounts provided. When a program has a fixed account layout but no upfront count check, any transaction providing fewer accounts than expected will panic at runtime.
This detector specifically targets the “fixed layout without validation” pattern: it triggers only when two or more accounts are accessed at constant indices and no length check is found. Single-account access is not flagged, as it does not suggest a fixed layout assumption.
Why This Is an Issue
Programs with fixed account layouts are the most common pattern on Solana (e.g., every instruction that requires a signer, a vault, and a token program account). Without an upfront count check, any of these programs can be crashed by providing insufficient accounts. This enables denial of service, wastes compute units before the panic occurs, and produces confusing error messages for legitimate users who misconfigure their transactions.
How to Resolve
pub fn process_swap(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
const EXPECTED_ACCOUNTS: usize = 5;
if accounts.len() < EXPECTED_ACCOUNTS {
return Err(ProgramError::NotEnoughAccountKeys);
}
let user = &accounts[0];
let source_token = &accounts[1];
let dest_token = &accounts[2];
let pool = &accounts[3];
let token_program = &accounts[4];
// All accesses are safe
Ok(())
}
Examples
Vulnerable Code
pub fn process_swap(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
// Accesses 5 accounts with no count validation
let user = &accounts[0];
let source_token = &accounts[1];
let dest_token = &accounts[2];
let pool = &accounts[3];
let token_program = &accounts[4]; // Panics with < 5 accounts
Ok(())
}
Fixed Code
pub fn process_swap(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
if accounts.len() < 5 {
return Err(ProgramError::NotEnoughAccountKeys);
}
let user = &accounts[0];
let source_token = &accounts[1];
let dest_token = &accounts[2];
let pool = &accounts[3];
let token_program = &accounts[4];
Ok(())
}
Sample Sigvex Output
[HIGH] Missing Account List Size Validation
Location: process_swap
Description: The function accesses accounts at constant indices [0, 1, 2, 3, 4]
(max index: 4), which requires at least 5 accounts, but does not
validate the account list size upfront.
CWE: CWE-754 (Improper Check for Unusual or Exceptional Conditions)
Detection Methodology
- Constant index collection: The detector identifies all account property accesses (
AccountData,AccountLamports,AccountOwner,AccountKey) that use constant indices, and records the set of unique indices. - Maximum index calculation: The highest constant index determines the minimum number of accounts required.
- Length check detection: The detector searches for conditional branches that compare a length-like expression against a constant, which would indicate upfront validation.
- Fixed layout threshold: A finding is generated only when two or more constant indices are accessed without a length check, indicating a fixed account layout assumption.
Limitations
False positives: Programs that validate account count through unconventional means (e.g., a helper function returning an error) may be flagged. Anchor programs receive reduced confidence because #[derive(Accounts)] enforces exact account count. False negatives: Programs that access accounts through variable indices (rather than constants) are not covered by this detector; see the account index bounds detector instead.
Related Detectors
- Account Index Bounds — detects individual variable index access without validation
- Account Iterator Bounds — detects unsafe iteration over account arrays