logo

Database

Improper resource allocation

Need

Prevention of integer overflow in arithmetic on request-controlled values

Context

• Usage of Rust 1.75+ for building application services

• Usage of the actix-web crate for handling HTTP requests

Description

1. Non compliant code

use actix_web::{get, web, HttpResponse};

const UNIT_PRICE_CENTS: u32 = 100;

#[get("/price/{quantity}")]
async fn price(path: web::Path<u32>) -> HttpResponse {
    let quantity = path.into_inner();
    // Wraps silently in release builds: 42949673 * 100 == 4...

The `price` handler below multiplies the `quantity` taken from the URL by a unit price, both as `u32`, with the `*` operator. Rust only checks integer overflow in debug builds. In release builds, which are the ones deployed, `*` silently wraps around modulo 2^32, so a quantity such as `42949673` makes `42949673 * 100` wrap to `4`. The attacker orders tens of millions of units for a total of 4 cents. The same wrapping can turn a size calculation into a tiny buffer, bypass a limit check, or produce a negative-looking balance. In debug builds, or with `overflow-checks` enabled, the same input makes the handler panic instead, which lets an attacker crash workers on demand.

2. Steps

• Validate request-controlled numbers against explicit business limits before using them in arithmetic.

• Use `checked_add`, `checked_sub`, `checked_mul` and `checked_div` on values that come from requests, and handle the `None` case.

• Widen integers, for example from `u32` to `u64`, before multiplying values that represent money, sizes or counts.

• Enable `overflow-checks = true` in the release profile of `Cargo.toml` so unchecked overflow panics instead of wrapping silently.

• Enable the `clippy::arithmetic_side_effects` lint in modules that handle prices, balances or buffer sizes.

3. Secure code example

use actix_web::{get, web, HttpResponse};

const UNIT_PRICE_CENTS: u64 = 100;
const MAX_QUANTITY: u32 = 10_000;

#[get("/price/{quantity}")]
async fn price(path: web::Path<u32>) -> HttpResponse {
    let quantity = path.into_inner();...

The corrected handler validates the quantity against a business limit before any arithmetic, and computes the total with `checked_mul` in `u64`. The explicit limit rejects requests that no legitimate customer would send with `400 Bad Request`. `checked_mul` returns `None` instead of wrapping or panicking, so even if the limits change later, an overflow becomes an error response rather than a wrong price. Widening to `u64` gives the calculation room for any valid order. The standard library also offers `saturating_*` and `overflowing_*` methods, and `overflow-checks = true` in the release profile turns any remaining unchecked arithmetic into a panic instead of a silent wrong value.