Transaction Size DoS
Overview
The transaction size DoS detector identifies unbounded account list iteration in CPI calls that can exceed Solana’s 1232-byte transaction size limit. Each account in a transaction consumes 32 bytes (pubkey) plus metadata, so exceeding roughly 30-35 accounts can cause transaction failures that attackers can exploit for denial-of-service.
For remediation guidance, see Transaction Size DoS Remediation.
Why This Is an Issue
Solana transactions are limited to 1232 bytes. Programs that construct CPI calls with dynamically-sized account lists controlled by user input can create transactions that exceed this limit. Attackers can exploit this by providing excessive account lists to force transaction failures, causing denial-of-service for legitimate users and wasting their transaction fees.
How to Resolve
Before (Vulnerable)
// Vulnerable: CPI with unbounded account list
pub fn process_batch(ctx: Context<Batch>, account_keys: Vec<Pubkey>) -> Result<()> {
let mut accounts = Vec::new();
for key in account_keys.iter() { // No upper bound
accounts.push(AccountMeta::new(*key, false));
}
invoke(&instruction, &accounts)?;
Ok(())
}
After (Fixed)
const MAX_ACCOUNTS: usize = 20;
pub fn process_batch(ctx: Context<Batch>, account_keys: Vec<Pubkey>) -> Result<()> {
require!(account_keys.len() <= MAX_ACCOUNTS, ErrorCode::TooManyAccounts);
let mut accounts = Vec::with_capacity(account_keys.len());
for key in account_keys.iter() {
accounts.push(AccountMeta::new(*key, false));
}
invoke(&instruction, &accounts)?;
Ok(())
}
Example JSON Finding
{
"detector": "transaction-size-dos",
"severity": "medium",
"confidence": 0.6,
"message": "CPI call with dynamically-sized account list without upper bound validation",
"location": { "function": "process_batch", "block": 1, "statement": 4 }
}
Detection Methodology
- CPI account list analysis: Identifies CPI calls where the account list is built dynamically from user input.
- Bounds checking: Verifies that dynamically-constructed account lists have maximum size validation.
- Loop-CPI pattern: Detects CPI calls inside loops without account count limits.
- User-controlled count: Tracks whether the account count derives from instruction data.
Limitations
False positives: Programs with small constant-size account lists may be flagged if the constant is not visible at bytecode level. False negatives: Transaction size issues caused by large instruction data rather than account counts are not detected.
Related Detectors
- DoS Compute Exhaustion – compute-based denial-of-service
- CPI In-Loop DoS – CPI calls in loops