- Category: arithmetic
- Severity: Medium
- Rule name:
arithmetic_overflow
S003 flags unchecked arithmetic operations that can overflow, underflow, or panic on a zero divisor:
- Binary operators:
+,-,*,/,%. - Compound assignment:
+=,-=,*=,/=,%=. - Custom math methods and calls:
.mul_div(),.fixed_point_mul(),.fixed_point_div(),.div_ceil()and their function-style equivalents.
It does not flag .checked_* / .saturating_* methods, comparison and bitwise operators, string concatenation, array-index arithmetic (buf[i + 1]), or code under #[test] / #[cfg(test)]. Findings are deduplicated to at most one per (function, operator) pair.
In Rust, integer overflow panics in debug builds and wraps silently in release builds. For a contract handling balances, either outcome is unacceptable: a panic locks state, and silent wraparound produces incorrect balances, unauthorized minting, or loss-of-funds rounding.
#![no_std]
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env};
#[contracttype]
pub enum DataKey {
Balance(Address),
}
#[contract]
pub struct Token;
#[contractimpl]
impl Token {
pub fn mint(env: Env, to: Address, amount: i128) {
let current: i128 = env
.storage()
.persistent()
.get(&DataKey::Balance(to.clone()))
.unwrap_or(0);
// S003: unchecked addition can overflow.
let new_balance = current + amount;
env.storage()
.persistent()
.set(&DataKey::Balance(to), &new_balance);
}
}#![no_std]
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env};
#[contracttype]
pub enum DataKey {
Balance(Address),
}
#[contract]
pub struct Token;
#[contractimpl]
impl Token {
pub fn mint(env: Env, to: Address, amount: i128) {
let current: i128 = env
.storage()
.persistent()
.get(&DataKey::Balance(to.clone()))
.unwrap_or(0);
// checked_add returns None on overflow.
let new_balance = current
.checked_add(amount)
.expect("mint: balance overflow");
env.storage()
.persistent()
.set(&DataKey::Balance(to), &new_balance);
}
}- Vector:
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L - Base score: 5.9
- Rating: Medium
Exploitation usually requires crafted boundary inputs (higher attack complexity), but a successful overflow can corrupt balances (high integrity impact).
- Replace unchecked operators with
.checked_add/.checked_sub/.checked_mul/.checked_div/.checked_remand handle theNonecase. - Where clamping is acceptable for non-financial values, use the
.saturating_*variants. - For custom fixed-point math, use checked wrappers (e.g.
.checked_mul_div). - Cast to a wider integer type before arithmetic when widening makes the operation provably safe.