CRITICAL axumrustjwt none algorithm

Jwt None Algorithm in Axum (Rust)

Jwt None Algorithm in Axum with Rust — how this specific combination creates or exposes the vulnerability

The JWT None algorithm vulnerability occurs when a server accepts an unsigned tokens (alg: none) and treats it as trusted. In Axum with Rust, this typically arises when a developer configures JSON Web Token validation but does not explicitly restrict which signing algorithms are permitted. If the validation layer is set to accept tokens without verifying a signature, an attacker can craft a token with alg: none, place arbitrary claims in the payload, and the server may incorrectly authorize access.

Consider an Axum handler that uses jsonwebtoken crate with permissive validation settings. The following example demonstrates an insecure configuration:

use axum::{routing::get, Router};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};

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

async fn handler(
    bearer: Option<axum::extract::Header<axum::http::headers::Authorization<axum::http::header::Bearer>>>
) -> String {
    let token = bearer.map(|h| h.token().to_string()).unwrap_or_default();
    let validation = Validation::new(Algorithm::None); // Insecure: allows none algorithm
    let _decoded = decode::<Claims>(&token, &DecodingKey::from_secret(&[]), &validation).unwrap();
    "authorized".to_string()
}

fn app() -> Router {
    Router::new().route("/protected", get(handler))
}

In this example, Validation::new(Algorithm::None) explicitly accepts tokens with no signature. An attacker can generate a token like eyJhbGciOiJub25lIn0.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxOTk5OTk5OTk5fQ. (header with alg: none, payload with elevated claims), send it to the endpoint, and bypass authentication entirely. This maps to the Authentication check in middleBrick, where unauthenticated attack surface testing would flag the endpoint as allowing unsigned tokens. The vulnerability is not in Axum itself, but in how the developer configures the validation logic, failing to restrict algorithms to a trusted set such as HS256 or RS256.

middleBrick’s LLM/AI Security and authentication checks would detect this misconfiguration during an unauthenticated scan, reporting that the API accepts the None algorithm. This creates a critical risk where session tokens or API access can be forged without credentials. Developers must ensure token validation explicitly rejects alg: none by whitelisting only required algorithms and validating the presence of a signature.

Rust-Specific Remediation in Axum — concrete code fixes

To remediate the JWT None algorithm issue in Axum, you must enforce strict algorithm validation and avoid permissive settings. The key is to initialize Validation with a specific, expected algorithm and to ensure the decoding key matches the server’s public or symmetric key.

Below is a secure Axum handler using HS256 (symmetric signing). It explicitly sets allowed algorithms and verifies the signature:

use axum::{routing::get, Router, extract::Extension};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, TokenData};
use serde::{Deserialize, Serialize};

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

async fn handler(
    TokenData(claims): TokenData<Claims>,
) -> String {
    format!("user: {}", claims.sub)
}

fn validation_key() -> DecodingKey {
    // In production, load this from a secure source (env var, secret manager)
    DecodingKey::from_secret("super-secret-key".as_ref())
}

fn validation() -> Validation {
    let mut validation = Validation::new(Algorithm::HS256);
    validation.validate_exp = true; // Ensure expiration is checked
    validation
}

async fn protected_handler(
    bearer: Option<axum::extract::Header<axum::http::headers::Authorization<axum::http::header::Bearer>>>
) -> Result<String, (axum::http::StatusCode, String)> {
    let token = bearer.map(|h| h.token().to_string()).ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing token".to_string()))?;
    let key = validation_key();
    let validation = validation();
    let token_data = decode::<Claims>(&token, &key, &validation).map_err(|e| (axum::http::StatusCode::UNAUTHORIZED, e.to_string()))?;
    Ok(handler(token_data).await)
}

fn app() -> Router {
    Router::new()
        .route("/protected", get(protected_handler))
}

This code uses Validation::new(Algorithm::HS256), which ensures only HS256-signed tokens are accepted. It also checks expiration and returns 401 on decode errors. For asymmetric keys (e.g., RS256), use DecodingKey::from_rsa_pem with a public PEM certificate.

In a microservices context, you can share the validation logic via a reusable module. The middlebrick CLI can scan your API endpoints to confirm that none accept the None algorithm. If you use the Pro plan, continuous monitoring will alert you if a future configuration change reintroduces the vulnerability.

Frequently Asked Questions

How can I test if my Axum API is vulnerable to the JWT None algorithm?
Send a JWT with header {"alg":"none"} and no signature to your endpoint. If the server returns a 200 with authorized behavior, it is vulnerable. Tools like middlebrick can automate this check during a scan.
Does using RS256 instead of HS256 prevent the None algorithm vulnerability?
No. The vulnerability is about accepting alg: none, not the choice of HS256 or RS256. You must explicitly configure validation to reject None algorithm regardless of the key type.