Critical Truncation
Detects integer truncation in security-critical operations including lamport transfers, account storage, and access control.
Critical Truncation
Overview
The critical truncation detector identifies integer truncation that flows into security-critical operations: lamport transfers, account data storage, and access control branches. Unlike the general integer truncation detector, this detector uses two-pass data flow analysis to trace truncated variables into sensitive sinks. Truncation in these contexts poses immediate security risks. For remediation steps, see the Critical Truncation Remediation.
Why This Is an Issue
When a truncated integer reaches a critical operation, the consequences are severe:
Financial context (Critical severity): A lamport transfer using a truncated amount can result in theft. For example, an attacker calls a function with amount 0x1_0000_0000 (4,294,967,296). After truncation to u32, this becomes 0. The transfer executes with amount zero while the program believes it transferred the full amount, draining the account.
Data integrity context (High severity): Truncating values before storing to account data corrupts program state. A token balance of 1,000,000,000 truncated to u16 becomes 51,712, permanently corrupting the account’s balance record.
Access control context (High severity): Truncating user IDs or role values before comparison can match privileged values. A user ID of 0x1234 truncated to u8 becomes 0x34. If admin role ID is 0x34, the attacker gains unauthorized access.
How to Resolve
// Before: Vulnerable -- truncated value in transfer
let amount: u32 = large_amount as u32; // Truncation
transfer_lamports(from, to, amount as u64)?; // Uses truncated value
// After: Fixed -- use full-width type
let amount: u64 = large_amount; // No truncation
transfer_lamports(from, to, amount)?;
Examples
Vulnerable Code: Truncated Transfer Amount
pub fn withdraw(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
let capped: u32 = amount as u32; // Truncation!
**accounts[0].try_borrow_mut_lamports()? -= capped as u64;
**accounts[1].try_borrow_mut_lamports()? += capped as u64;
Ok(())
}
Vulnerable Code: Truncated Storage Value
pub fn update_balance(accounts: &[AccountInfo], new_balance: u64) -> ProgramResult {
let stored: u16 = new_balance as u16; // Truncation!
let data = &mut accounts[0].try_borrow_mut_data()?;
data[0..2].copy_from_slice(&stored.to_le_bytes()); // Corrupted state
Ok(())
}
Fixed Code
pub fn withdraw(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
// Use u64 throughout -- no truncation
let balance = **accounts[0].try_borrow_lamports()?;
if balance < amount {
return Err(ProgramError::InsufficientFunds);
}
**accounts[0].try_borrow_mut_lamports()? -= amount;
**accounts[1].try_borrow_mut_lamports()? += amount;
Ok(())
}
Example JSON Finding
{
"detector": "critical-truncation",
"severity": "critical",
"confidence": 0.80,
"title": "Integer Truncation in Lamport Transfer",
"description": "A truncated integer value is used as the amount in a lamport transfer operation.",
"cwe_ids": [681]
}
Detection Methodology
- Pass 1 — Truncation discovery: Identifies all assignment statements containing type casts from larger to smaller integer types, recording which variables hold truncated values.
- Pass 2 — Sink analysis: Traces truncated variables into critical operations:
TransferLamportswith truncated amount (Critical severity)StoreAccountDatawith truncated value (High severity)Branchconditions containing truncated variables (High severity)
- Data flow tracking: Follows truncated variables through binary operations and nested expressions to detect indirect usage.
Limitations
False positives: Truncation that is bounded by prior validation (e.g., require!(amount <= u32::MAX as u64)) before the cast may still be flagged if the validation occurs in a different function. Anchor programs with typed fields receive reduced confidence. False negatives: Truncated values passed through function calls (CPI) or stored to intermediate variables through complex chains may lose tracking. Only single-function analysis is performed.
Related Detectors
- Integer Truncation — detects all unsafe truncation regardless of context
- Integer Overflow — detects arithmetic overflow
- Lamport Underflow — detects lamport balance underflow