Insufficient Data Length Check
Detects account data access without sufficient length validation, which can cause buffer overflows or runtime panics.
Insufficient Data Length Check
Overview
Remediation Guide: How to Fix Insufficient Data Length Check
The insufficient data length check detector identifies Solana programs that read or write account data without first verifying that the account’s data buffer is large enough for the operation. Unlike the instruction data length detector which focuses on the instruction payload, this detector targets account data — the persistent storage associated with each Solana account.
When a program reads 8 bytes from an account at offset 32 but the account only has 36 bytes of data, the access exceeds the buffer boundary. The detector tracks both reads and writes, compares the required access size against any length validation that exists, and flags operations where the validated size is insufficient.
Why This Is an Issue
Account data is allocated at account creation and can be reallocated. An attacker who controls account creation can provide an account with less data than the program expects. Without a length check, this causes out-of-bounds reads (potentially leaking data from adjacent memory), out-of-bounds writes (corrupting adjacent account data), or runtime panics that crash the program.
How to Resolve
pub fn process(accounts: &[AccountInfo]) -> ProgramResult {
let data_account = &accounts[0];
let data = data_account.try_borrow_data()?;
// Validate length before access
const REQUIRED_SIZE: usize = 40; // 8 (discriminator) + 32 (pubkey)
if data.len() < REQUIRED_SIZE {
return Err(ProgramError::InvalidAccountData);
}
let stored_key = Pubkey::new_from_array(data[8..40].try_into().unwrap());
Ok(())
}
Examples
Vulnerable Code
pub fn read_vault(accounts: &[AccountInfo]) -> ProgramResult {
let vault = &accounts[0];
let data = vault.try_borrow_data()?;
// No length check -- panics if account data is too short
let balance = u64::from_le_bytes(data[0..8].try_into().unwrap());
let authority = Pubkey::new_from_array(data[8..40].try_into().unwrap());
Ok(())
}
Fixed Code
pub fn read_vault(accounts: &[AccountInfo]) -> ProgramResult {
let vault = &accounts[0];
let data = vault.try_borrow_data()?;
if data.len() < 40 {
return Err(ProgramError::InvalidAccountData);
}
let balance = u64::from_le_bytes(data[0..8].try_into().unwrap());
let authority = Pubkey::new_from_array(data[8..40].try_into().unwrap());
Ok(())
}
Sample Sigvex Output
[HIGH] Insufficient Account Data Length Check
Location: read_vault (block 0, stmt 1)
Description: Account data is accessed (read, offset+size=40 bytes)
without validating sufficient data length (validated: 0 bytes).
CWE: CWE-129 (Improper Validation of Array Index)
Detection Methodology
- Account data access tracking: The detector identifies all
AccountDataread operations andStoreAccountDatawrite operations, recording the offset and access size for each. - Length validation extraction: It searches for conditional branches that compare an account’s data length against a constant (e.g.,
data.len() >= 40). - Sufficiency comparison: For each access, the detector compares the total bytes needed (offset + access size) against the validated minimum. If the validated size is less than the required size, a finding is generated.
Limitations
False positives: Anchor programs that use typed account deserialization (Account<'info, T>) validate length automatically, but the detector may still flag bytecode-level access patterns. Confidence is reduced for Anchor programs. False negatives: Length checks performed through helper functions or stored in variables that are later compared may not be tracked without interprocedural analysis.
Related Detectors
- Instruction Data Length — detects missing instruction data buffer length validation
- Account Index Bounds — detects missing bounds checks on account array access