HIGH integer overflowactixjwt tokens

Integer Overflow in Actix with Jwt Tokens

Integer Overflow in Actix with Jwt Tokens

Integer overflow in Actix web applications becomes critical when handling JWT token metadata such as expiration (exp), not-before (nbf), or issued-at (iat) claims represented as NumericDate (seconds since epoch). In Rust, arithmetic used to compute token lifetimes or validate time windows can overflow a u32 or u64 when values are cast, added, or multiplied, leading to an invalidation of security boundaries. An attacker can supply a crafted token with an extreme exp value that, when combined with arithmetic in application code, wraps to a seemingly valid timestamp in the past, bypassing expiration checks and enabling token replay or long-term access beyond intended scope.

Consider an Actix handler that computes a session TTL by adding a user-supplied lifetime to the current Unix time:

use actix_web::{web, HttpResponse};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    exp: usize,
}

// Risky: adding user-supplied lifetime as usize can overflow
async fn login_handler(
    body: web::Json<Claims>,
) -> HttpResponse {
    let now = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_secs() as usize;
    // If body.lifetime is large, `now + body.lifetime` may overflow in debug builds or produce wrong values in release
    let exp = now + body.lifetime; // potential usize overflow
    let token = encode(
        &Header::default(),
        &Claims { sub: body.sub.clone(), exp },
        &EncodingKey::from_secret("secret".as_ref()),
    );
    match token {
        Ok(t) => HttpResponse::Ok().body(t),
        Err(_) => HttpResponse::BadRequest().finish(),
    }
}

If body.lifetime is large (e.g., near usize::MAX), the addition wraps, producing a small exp that appears valid. During verification, the token may be accepted despite being expired or not-yet-valid, undermining the intended time-bound access control. This pattern is especially problematic when combined with unchecked deserialization or when using smaller integer types (u32) for legacy token parsers. The vulnerability maps to OWASP API Top 10:2023 API1:2023 Broken Object Level Authorization when overflow leads to authorization bypass, and it can be flagged by spec-aware scans that cross-reference OpenAPI definitions with runtime behavior.

middleBrick detects such risks by analyzing the unauthenticated attack surface and cross-referencing spec definitions with observed arithmetic patterns. In the context of JWT handling, findings may highlight missing bounds checks or unsafe numeric conversions, providing remediation guidance rather than attempting to fix or block traffic. This aligns with the platform’s focus on detection and reporting, while tools like the CLI (middlebrick scan <url>) or GitHub Action can integrate these checks into development workflows.

Jwt Tokens-Specific Remediation in Actix

Remediation centers on preventing integer overflow during time calculations and ensuring strict validation of JWT claims. Use checked arithmetic (e.g., checked_add) and prefer u64 for epoch-based timestamps to avoid wrapping. Validate exp, nbf, and iat against a trusted clock and enforce reasonable bounds relative to the token issuance time.

Below is a secure Actix handler example that avoids overflow and validates token metadata:

use actix_web::{web, HttpResponse};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, Header};
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    exp: usize,
    nbf: usize,
    iat: usize,
}

fn current_unix_secs() -> Option {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .ok()
        .map(|d| d.as_secs())
}

// Safe: uses checked arithmetic and proper validation
async fn login_handler(
    body: web::Json<Claims>,
) -> HttpResponse {
    let now = match current_unix_secs() {
        Some(t) => t,
        None => return HttpResponse::InternalServerError().finish(),
    };
    // Validate lifetime bounds before use
    let lifetime = body.lifetime;
    if lifetime == 0 || lifetime > 30_000 { // e.g., max 30 seconds for this example policy
        return HttpResponse::BadRequest().body("invalid lifetime");
    }
    // Use checked addition to prevent overflow
    let exp = match now.checked_add(lifetime as u64) {
        Some(t) => t,
        None => return HttpResponse::BadRequest().body("arithmetic overflow"),
    };
    let nbf = now;
    let iat = now;
    let token = match encode(
        &Header::default(),
        &Claims { sub: body.sub.clone(), exp: exp as usize, nbf: nbf as usize, iat: iat as usize },
        &EncodingKey::from_secret("secret".as_ref()),
    ) {
        Ok(t) => t,
        Err(_) => return HttpResponse::BadRequest().finish(),
    };
    // Verify with strict validation
    let mut validation = Validation::new(Algorithm::HS256);
    validation.validate_exp = true;
    validation.validate_nbf = true;
    validation.validate_iat = true;
    match decode::<Claims>(&token, &DecodingKey::from_secret("secret".as_ref()), &validation) {
        Ok(token_data) => {
            // Additional business checks, e.g., max session window
            if token_data.claims.exp.saturating_sub(token_data.claims.iat) > 30_000 {
                return HttpResponse::BadRequest().body("token window too large");
            }
            HttpResponse::Ok().body(token_data.claims.sub)
        }
        Err(_) => HttpResponse::Unauthorized().finish(),
    }
}

Key practices:

  • Use checked_add or similar safe arithmetic to avoid wrapping.
  • Enforce upper bounds on lifetimes and reject tokens with exp/nbf/iat values that fall outside acceptable windows.
  • Prefer u64 for epoch arithmetic and convert to usize only when interfacing with APIs that require it, ensuring lossless conversions.
  • Leverage the jsonwebtoken crate’s validation flags and perform additional business checks after decoding.

These measures reduce the risk of token validation bypass due to numeric overflow and align with secure coding guidelines for time-based claims.

Frequently Asked Questions

How does middleBrick detect integer overflow risks in JWT handling?
middleBrick scans the unauthenticated attack surface and cross-references OpenAPI/Swagger specifications with observed runtime patterns. It flags unsafe arithmetic (e.g., unchecked addition of user-controlled lifetimes) and missing bounds checks on JWT claims like exp/nbf/iat, providing remediation guidance rather than attempting to fix the service.
Can I integrate overflow checks into CI/CD for Actix APIs handling JWTs?
Yes. Using the GitHub Action, you can add API security checks to your CI/CD pipeline and fail builds if risk scores drop below your threshold. The CLI (middlebrick scan <url>) also supports JSON output for scripting, and the Pro plan includes continuous monitoring with alerts for score regressions.