HIGH axumrusttoken replay

Token Replay in Axum (Rust)

Token Replay in Axum with Rust — how this specific combination creates or exposes the vulnerability

Token replay in Axum with Rust occurs when a valid authentication token (e.g., a JWT or session identifier) can be captured and reused by an attacker to impersonate the original caller. Because Axum is a Rust web framework, developers often rely on strong type safety and compile-time guarantees, which may lead to assuming runtime behavior is automatically secure. However, if token validation is implemented only at the ingress point and not tied to a per-request nonce or timestamp, an intercepted token remains valid for subsequent requests.

In Rust-based services built with Axum, token handling frequently involves middleware that deserializes and verifies tokens (for example using jsonwebtoken or axum-extra). If the middleware places the claims into request extensions without ensuring freshness, an attacker who obtains a token (e.g., via logs, client-side leakage, or network sniffing in a non-TLS-terminated path) can replay that token against endpoints that do not enforce additional anti-replay controls. This is especially relevant for unauthenticated scan scenarios where an exposed endpoint accepts a token in headers and does not check for replays, aligning with the kinds of unauthenticated attack surface assessments middleBrick performs.

Certain API security checks performed by middleBrick, such as BOLA/IDOR and Authentication, can surface token replay risks when replayed requests yield different or unauthorized data access. For instance, a replayed token used with a different resource identifier (e.g., changing a numeric ID in a URL) might map to another user’s data if ownership checks are missing. The framework’s ergonomics do not inherently prevent this; it depends on how validation and authorization are wired into Axum’s extractor and middleware pipeline.

Consider an endpoint that accepts a bearer token via an Authorization header and uses a Rust extractor to parse it. If the token is verified but the implementation does not include a one-time-use mechanism, an attacker can replay the same HTTP request with the same token and receive the same response. middleBrick’s unauthenticated scan can detect such endpoints by observing idempotent responses to repeated requests that should have been protected by freshness checks or binding to client context.

Rust-Specific Remediation in Axum — concrete code fixes

To mitigate token replay in Axum with Rust, ensure each token validation includes freshness and, where appropriate, binding to the request context. Prefer short-lived tokens and validate not only the signature but also the iat (issued at) and exp (expiration) claims on every request. For replay protection, incorporate a server-side or distributed cache of recently seen token identifiers (e.g., JWT jti claim) with a short TTL, and reject tokens whose identifier has already been processed.

Below is a concrete Axum example using jsonwebtoken and axum::extract::Extension to enforce expiration and a simple in-memory replay cache. In production, replace the in-memory store with a shared, scalable store (e.g., Redis) to work correctly across multiple worker threads and instances.

use axum::{async_trait, extract::FromRequest, http::Request, response::Response, Extension, TypedHeader};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::sync::Arc;
use tokio::sync::RwLock;

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

#[derive(Debug, Clone)]
struct ReplayCache(Arc>>);

impl ReplayCache {
    fn new() -> Self {
        Self(Arc::new(RwLock::new(HashSet::new())))
    }

    async fn seen(&self, jti: &str) -> bool {
        let cache = self.0.read().await;
        cache.contains(jti)
    }

    async fn mark_seen(&self, jti: String) {
        let mut cache = self.0.write().await;
        cache.insert(jti);
    }
}

async fn validate_token(
    TypedHeader(auth_header): TypedHeader<axum::http::HeaderValue>,
    Extension(cache): Extension<ReplayCache>,
) -> Result<Claims, axum::http::StatusCode> {
    let token = auth_header
        .to_str()
        .map_err(|_| axum::http::StatusCode::UNAUTHORIZED)?
        .strip_prefix("Bearer ")
        .ok_or(axum::http::StatusCode::UNAUTHORIZED)?;

    let mut validation = Validation::new(Algorithm::HS256);
    validation.validate_exp = true;
    let token_data = decode::

In this example, the validate_token extractor verifies expiration and checks a replay cache using the JWT jti claim. If a token has already been seen within the cache’s TTL, the request is rejected with 403 Forbidden. This pattern aligns with the kinds of findings middleBrick reports under Authentication and BOLA/IDOR checks, providing clear remediation guidance to bind tokens to nonces and short lifetimes.

Additionally, prefer HTTPS to prevent token interception, rotate signing keys periodically, and avoid embedding sensitive data in tokens. If your threat model requires stronger binding, tie token usage to client IP or TLS session tickets, but be mindful of operational tradeoffs such as load balancer transparency and IPv6 variability.

Frequently Asked Questions

Can token replay happen even when tokens are cryptographically valid in Axum Rust services?
Yes. Cryptographic validity does not prevent replay unless you enforce freshness (exp/iat), one-time use (jti), or binding to a client context. Axum does not enforce these by default; you must add them via middleware or extractors.
Does middleBrick detect token replay risks in unauthenticated scans of Axum APIs?
Yes. middleBrick’s Authentication and BOLA/IDOR checks can flag endpoints that accept static tokens and return different data upon replay, helping you identify missing anti-replay controls without requiring authenticated access.