Division by Zero
Detects division and modulo operations where the divisor may be zero, causing runtime panics and DoS vulnerabilities.
Division by Zero
Overview
The division by zero detector identifies division and modulo operations where the divisor is user-controlled and may be zero. Division by zero causes a runtime panic in Solana programs, crashing the transaction. Attackers can exploit this for denial-of-service (DoS) attacks by crafting inputs that trigger the panic. For remediation steps, see the Division by Zero Remediation.
Why This Is an Issue
In Solana’s BPF runtime, division by zero causes an immediate program panic. Unlike arithmetic overflow (which wraps silently in release mode), division by zero always crashes. This creates two classes of vulnerability:
- DoS attacks: An attacker submits transactions with zero divisors to repeatedly crash the program. If the program is a critical DeFi protocol, this disrupts all operations including liquidations, withdrawals, and governance votes.
- Logic bugs: Constant zero divisors indicate dead code or implementation errors that will always crash when reached.
The detector distinguishes between:
- Constant zero divisors (Critical): Division by literal
0— always a definite bug. - User-controlled divisors (High for division, Medium for modulo): Values loaded from account data, parameters, or memory without prior zero validation.
- Validated divisors (Safe): Variables checked with
!= 0,> 0, or>= 1before use.
How to Resolve
// Before: Vulnerable -- user-controlled divisor without check
let rate = load_from_account(accounts)?;
let result = total_amount / rate; // Panics if rate == 0
// After: Fixed -- validate before division
let rate = load_from_account(accounts)?;
if rate == 0 {
return Err(ProgramError::InvalidArgument);
}
let result = total_amount / rate;
Examples
Vulnerable Code
pub fn distribute_rewards(
accounts: &[AccountInfo],
total_reward: u64,
num_stakers: u64, // User-provided
) -> ProgramResult {
// Panics if num_stakers == 0
let per_staker = total_reward / num_stakers;
let remainder = total_reward % num_stakers;
for i in 0..num_stakers {
distribute_to_staker(accounts, i, per_staker)?;
}
Ok(())
}
Fixed Code
pub fn distribute_rewards(
accounts: &[AccountInfo],
total_reward: u64,
num_stakers: u64,
) -> ProgramResult {
if num_stakers == 0 {
return Err(ProgramError::InvalidArgument);
}
let per_staker = total_reward
.checked_div(num_stakers)
.ok_or(ProgramError::ArithmeticOverflow)?;
let remainder = total_reward
.checked_rem(num_stakers)
.ok_or(ProgramError::ArithmeticOverflow)?;
for i in 0..num_stakers {
distribute_to_staker(accounts, i, per_staker)?;
}
Ok(())
}
Example JSON Finding
{
"detector": "division-by-zero",
"severity": "high",
"confidence": 0.80,
"title": "Potential Division by Zero on User Input",
"description": "Division operation uses a user-controlled value as the divisor without explicit zero validation.",
"cwe_ids": [369]
}
Detection Methodology
- Early exit optimization: Skips functions with no division or modulo operations (including 32-bit variants
Div32,Mod32). - Validated variable tracking: Scans branch conditions (both statement-level and terminator-level) for patterns like
var != 0,var > 0, andvar >= 1, marking these variables as validated. - User-controlled tracking: Identifies variables derived from parameters, memory loads, and account data reads, propagating taint through assignments.
- Divisor analysis: For each division/modulo operation, checks whether the divisor is a non-zero constant (safe), a validated variable (safe), or an unvalidated user-controlled value (flagged).
Limitations
False positives: Variables validated in called functions or via complex conditional logic (e.g., if a > 0 && b > 0 followed by a / b) may not be recognized as validated. Division by variables that are structurally non-zero (e.g., enum discriminants that cannot be zero) will be flagged. False negatives: Division operations performed inside CPI calls are not analyzed. Variables validated through saturating arithmetic or clamping (max(divisor, 1)) are not recognized as validated.
Related Detectors
- Unchecked Arithmetic — detects general unchecked arithmetic
- Integer Overflow — detects arithmetic overflow
- Unchecked Fee/Rent Math — detects unchecked math in fee calculations