Unsafe Deserialization
Detects potentially unsafe account data access patterns without bounds checking.
Unsafe Deserialization
Overview
Remediation Guide: How to Fix Unsafe Deserialization
The unsafe deserialization detector identifies Solana programs that access account data without bounds checking. When account data is read or written using variable offsets without validating that the offset is within the account’s data length, the program may panic from out-of-bounds access or write beyond the allocation boundary.
Sigvex flags variable-offset reads and writes to account data, as well as large fixed-size writes that may exceed the account’s allocated space.
Why This Is an Issue
- Program panics: out-of-bounds reads cause the BPF runtime to abort the program, wasting compute budget and failing the transaction.
- Out-of-bounds writes: writing beyond the account boundary corrupts adjacent memory, potentially modifying other program state.
- Denial of service: an attacker can craft instruction data with malicious offsets to reliably crash the program.
CWE mapping: CWE-125 (Out-of-bounds Read), CWE-787 (Out-of-bounds Write).
How to Resolve
Native Solana
pub fn read_field(account: &AccountInfo, offset: usize, size: usize) -> ProgramResult {
let data = account.data.borrow();
// Validate bounds before access
require!(offset + size <= data.len(), ProgramError::InvalidAccountData);
let value = &data[offset..offset + size];
// Process value...
Ok(())
}
Anchor
// Anchor handles deserialization via Borsh with automatic bounds checking
#[account]
pub struct MyState {
pub authority: Pubkey,
pub balance: u64,
}
Examples
Vulnerable
let data = account.data.borrow();
let offset = instruction_data[0] as usize; // User-controlled offset
let value = u64::from_le_bytes(data[offset..offset + 8].try_into()?); // No bounds check!
Fixed
let data = account.data.borrow();
let offset = instruction_data[0] as usize;
require!(offset + 8 <= data.len(), InvalidAccountData);
let value = u64::from_le_bytes(data[offset..offset + 8].try_into()?);
JSON Finding
{
"detector": "unsafe-deserialization",
"severity": "Medium",
"confidence": 0.65,
"title": "Variable Offset Account Data Read",
"description": "Account data is read with a variable offset without bounds checking.",
"cwe": [125]
}
Detection Methodology
The detector scans AccountData expressions and StoreAccountData statements for variable offsets (non-constant expressions). It also flags large fixed-size writes (8 bytes) that could exceed small accounts. The analysis recurses into nested expressions to catch indirect account data access patterns.
Limitations
- Constant offsets are not flagged even if they exceed typical account sizes.
- The detector cannot verify whether bounds checks exist in helper functions.
- Anchor programs receive reduced confidence since Borsh deserialization includes built-in bounds checking.
Related Detectors
- Unchecked Deserialization - detects deserialization without error handling.
- Zero Copy Deserialization - detects unsafe zero-copy patterns.
- Deserialization Endianness - detects endianness mismatches.