Integer Overflow (SVM) Remediation
How to fix integer overflow and underflow vulnerabilities in Solana programs.
Integer Overflow (SVM) Remediation
Overview
Related Detector: Integer Overflow (SVM)
Solana programs compiled in release mode do not panic on integer overflow by default. A u64 addition that wraps around to zero produces a silent corrupt value that the rest of the program treats as authoritative — burning balances, deleting vesting amounts, or unlocking funds.
Recommended Fix
Before (Vulnerable)
pub fn deposit(state: &mut Vault, amount: u64) -> ProgramResult {
state.total_deposits += amount; // wraps silently
state.user_balance += amount; // wraps silently
Ok(())
}
After (Fixed)
pub fn deposit(state: &mut Vault, amount: u64) -> ProgramResult {
state.total_deposits = state
.total_deposits
.checked_add(amount)
.ok_or(ProgramError::ArithmeticOverflow)?;
state.user_balance = state
.user_balance
.checked_add(amount)
.ok_or(ProgramError::ArithmeticOverflow)?;
Ok(())
}
Every fallible arithmetic operation must use checked_add, checked_sub, checked_mul, or checked_div and propagate the None case as an explicit error.
Alternative Mitigations
Enable overflow-checks = true in Cargo.toml
[profile.release]
overflow-checks = true
This makes every arithmetic operation panic on overflow even in release builds. The cost is a small CU increase per arithmetic instruction; the benefit is defense in depth against operations that were missed during code review.
Use saturating_* for known-safe ceilings
let new_supply = current_supply.saturating_add(reward);
Use this only when capping at u64::MAX is the correct semantic — for example, statistic counters that should not wrap. Never use it for balance accounting.
Widen intermediate computations
let result = ((a as u128) * (b as u128) / (denominator as u128)) as u64;
Promote to u128 for multiplication, then check that the final cast fits:
let intermediate = (a as u128).checked_mul(b as u128).ok_or(...)?
.checked_div(denominator as u128).ok_or(...)?;
if intermediate > u64::MAX as u128 {
return Err(ProgramError::ArithmeticOverflow);
}
Common Mistakes
Using wrapping_* to silence the linter. wrapping_add documents that wraparound is intentional. It is almost never the correct behavior for token amounts.
Mixing checked and unchecked operations in the same expression. A single + in the middle of a checked chain undoes the protection. Use only checked methods on the entire expression.
Forgetting subtraction. Underflow on u64 is just as exploitable as overflow. checked_sub is required wherever subtraction touches user-controlled values.