HIGH integer overflowactixhmac signatures

Integer Overflow in Actix with Hmac Signatures

Integer Overflow in Actix with Hmac Signatures

Integer overflow in Actix when HMAC signatures are used for request authentication can lead to signature validation bypass and security risk. In Rust, arithmetic operations on primitive integer types do not automatically saturate or wrap in checked mode; they wrap in both debug and release builds unless explicitly guarded. When an Actix application parses a numeric identifier (e.g., a resource ID or version) from user input and then uses it in a computation that affects the size of data or the length of a payload involved in HMAC generation, an attacker can supply values that cause overflow. This can change the length of the signed payload, producing a mismatched HMAC that an unchecked comparison might incorrectly accept, or it can cause logic errors that skip authorization checks.

Consider an endpoint that accepts user_id and a timestamp to build a canonical string for signing with HMAC-SHA256. If user_id is added to a base value without checking for overflow, a large crafted integer can wrap to a small value, changing the canonical representation and the resulting HMAC. Because the server recomputes the HMAC using the parsed integers, an attacker can craft inputs that intentionally overflow to produce a predictable signature match. This is especially dangerous when the integer is also used to size buffers or to index into arrays, potentially enabling memory corruption or information leakage. The vulnerability is not in HMAC itself but in how integer arithmetic feeds into the data that HMAC signs and verifies.

An example scenario: an API uses a 32-bit unsigned integer for a nonce combined with a timestamp to build the signed payload. A request with a nonce near u32::MAX can overflow when incremented or added, wrapping to zero or a small number. If the server does not detect this, the attacker may reuse a valid nonce value or force the nonce to collide, undermining replay protection. Because Actix applications often deserialize JSON or form data directly into Rust structs, unchecked deserialization combined with unchecked arithmetic creates a clear path to exploit. The risk is compounded when the HMAC key is static and the same key is used across many requests, allowing an attacker to test crafted overflow patterns offline.

To detect this class of issue, middleBrick scans the unauthenticated attack surface of an Actix endpoint and correlates findings from the Input Validation and BOLA/IDOR checks with the presence of HMAC-based authentication. It examines how numeric fields are used in signature construction and flags missing bounds checks or unchecked arithmetic. The scanner does not modify the application; it reports findings with severity and remediation guidance, helping developers understand how integer handling interacts with HMAC usage.

Hmac Signatures-Specific Remediation in Actix

Remediation focuses on preventing integer overflow before values participate in HMAC computation and ensuring that HMAC verification is robust and side-channel resistant. Use checked arithmetic for any integer derived from untrusted input, and reject inputs that would overflow before they are used to build the signed payload. Prefer fixed-size or well-bounded numeric types, and validate ranges explicitly. When constructing the string to sign, serialize values using a canonical, deterministic format (e.g., decimal strings without extra whitespace) to avoid ambiguity. Use a constant-time comparison for HMAC verification to prevent timing attacks, and avoid branching on secret data.

Below are concrete code examples for secure HMAC handling in Actix. The first example shows safe parsing and checked arithmetic before building the signature base string. The second shows middleware-like verification that uses fixed-length hex encoding and constant-time comparison. These snippets assume usage of hmac, sha2, and ring or subtle for constant-time operations.

use actix_web::{web, HttpResponse, Result};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use subtle::ConstantTimeEq;

type HmacSha256 = Hmac<Sha256>;

// Safe construction of the data to sign using checked arithmetic.
fn build_signed_data(user_id: u64, nonce: u64, timestamp: u64, extra: &str) -> Option<String> {
    // Ensure values fit within expected bounds before using them.
    let bounded_id = (user_id <= 1_000_000).then_some(user_id)?;
    let bounded_nonce = (nonce < 1_000_000_000).then_some(nonce)?;
    // Use checked operations to detect overflow.
    let combined = bounded_id.checked_add(bounded_nonce)?;
    let total = combined.checked_add(timestamp)?;
    Some(format!("{:016x}{:016x}{:016x}{}", bounded_id, bounded_nonce, timestamp, extra))
}

// Verify HMAC with constant-time comparison.
fn verify_signature(
    payload: &str,
    received_sig: &str,
    key: &[u8;\u00a032],
) -> bool {
    let mut mac = HmacSha256::new_from_slice(key).expect("HMAC key size is valid");
    mac.update(payload.as_bytes());
    let computed = mac.finalize();
    let computed_bytes = computed.into_bytes();
    // Decode received hex signature.
    let decoded = hex::decode(received_sig).ok()?;
    // Constant-time equality check.
    subtle::ConstantTimeEq::ct_eq(computed_bytes.as_slice(), decoded.as_slice()).into()
}

// Example handler using safe construction and verification.
async fn secure_endpoint(
    web::Json(params): web::Json<serde_json::Value>,
) -> Result<HttpResponse> {
    let user_id = params.get("user_id")?.as_u64().ok_or_else(|| actix_web::error::ErrorBadRequest("invalid user_id"))?;
    let nonce = params.get("nonce")?.as_u64().ok_or_else(|| actix_web::error::ErrorBadRequest("invalid nonce"))?;
    let timestamp = params.get("timestamp")?.as_u64().ok_or_else(|| actix_web::error::ErrorBadRequest("invalid timestamp"))?;
    let extra = params.get("extra")?.as_str().unwrap_or("");

    let data_to_sign = build_signed_data(user_id, nonce, timestamp, extra)
        .ok_or_else(|| actix_web::error::ErrorBadRequest("integer overflow or invalid range"))?;

    let key = hex::decode("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")
        .map_err(|_| actix_web::error::ErrorBadRequest("invalid key"))?;
    let key_arr: [u8; 32] = key.try_into().map_err(|_| actix_web::error::ErrorBadRequest("invalid key length"))?;

    let received_sig = params.get("signature")?.as_str().ok_or_else(|| actix_web::error::ErrorBadRequest("missing signature"))?;
    if verify_signature(&data_to_sign, received_sig, &key_arr) {
        Ok(HttpResponse::Ok().body("verified"))
    } else {
        Err(actix_web::error::ErrorBadRequest("invalid signature"))
    }
}

Key remediation practices: always validate and bound inputs before using them in HMAC construction; use checked arithmetic to prevent overflow; encode values in a canonical, deterministic way; and perform HMAC verification with constant-time comparison. middleBrick’s scans highlight missing bounds checks and unsafe arithmetic when HMAC-based authentication is present, enabling you to address these patterns before deployment.

Frequently Asked Questions

Why does integer overflow affect HMAC security in Actix?
Integer overflow can alter the data that is included in the HMAC-signed payload. If an attacker can cause overflow, they may craft inputs that change the canonical representation, leading to a different HMAC that can be matched or bypassed by the server, undermining authentication integrity.
What is the best way to prevent integer overflow when building HMAC input in Actix?
Use checked arithmetic (e.g., checked_add), validate that untrusted integers are within expected bounds before using them, and serialize values using a deterministic canonical format. Reject out-of-range values early and perform HMAC verification with a constant-time comparison to avoid timing leaks.