HIGH dangling dnsaxumjwt tokens

Dangling Dns in Axum with Jwt Tokens

Dangling Dns in Axum with Jwt Tokens — how this specific combination creates or exposes the vulnerability

A dangling DNS configuration combined with JSON Web Token (JWT) handling in an Axum service can expose authentication bypass or host confusion vulnerabilities. Axum is a Rust web framework where routes and middleware are explicitly composed; if JWT validation logic is applied inconsistently across routes or relies on hostname-based routing, an attacker can exploit DNS records that point to unexpected or leftover endpoints.

In this scenario, a service might validate JWTs in one route group under a primary domain (api.example.com) but omit validation in another route that is accidentally exposed via a dangling DNS entry (e.g., dev.api.example.com or an orphaned subdomain). Because Axum matches routes by path and method, not by hostname, a request to the dangling subdomain can bypass intended authorization checks if the JWT middleware is not applied uniformly. Additionally, if the service uses hostname-sensitive claim validation (such as custom audience or issuer checks that include the hostname), an attacker controlling a dangling DNS record can present a token that appears valid for the intended hostname but is accepted by the misconfigured endpoint.

During a middleBrick scan, this combination is tested by probing unauthenticated endpoints and analyzing OpenAPI specs and runtime behavior for missing authentication on routes that should require JWTs. The scanner checks for inconsistent auth application across hosts and flags cases where hostname-based routing or claim validation is not enforced. Real-world attack patterns like token replay to overlooked subdomains, or exploitation of misconfigured CNAME records that point to deprecated services, map to the Authentication and BOLA/IDOR checks. These tests reveal whether JWT validation is tied to the intended endpoint surface and whether dangling DNS records expose weaker paths.

An example of unsafe Axum routing where JWT middleware is applied only to a specific router that does not cover all intended paths:

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

async fn validate_token(headers: &axum::http::HeaderMap) -> Result, (axum::http::StatusCode, String)> {
    let token = headers.get("authorization")
        .and_tx(|h| h.to_str().ok())
        .and_then(|s| s.strip_prefix("Bearer "))
        .ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing token".to_string()))?;
    let decoding_key = DecodingKey::from_secret("secret".as_ref());
    let validation = Validation::new(Algorithm::HS256);
    decode::(token, &decoding_key, &validation).map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Invalid token".to_string()))
}

// Protected router with JWT middleware applied
fn protected_router() -> Router {
    Router::new()
        .route("/me", get(|headers: axum::http::HeaderMap| async move {
            validate_token(&headers).await.map(|data| format!("user: {}", data.claims.sub))
        }))
        .layer(axum::middleware::from_fn_with_state((), |_state, request, next| async move {
            // middleware that calls validate_token and passes claims
            next.run(request).await
        }))
}

// Public router without JWT enforcement
fn public_router() -> Router {
    Router::new()
        .route("/health", get(|| async { "ok" }))
}

fn app() -> Router {
    Router::new()
        .merge(protected_router())
        .merge(public_router())
}

In this example, if a dangling DNS record points a subdomain to the public router or to a route that merges in a different router without JWT enforcement, tokens may not be validated. Remediation is to ensure JWT middleware is applied at the top-level router or via a tower layer that covers all intended entry points, and to validate hostname claims explicitly.

Jwt Tokens-Specific Remediation in Axum — concrete code fixes

To remediate JWT-related issues in Axum, enforce token validation consistently across all routes and validate hostname-sensitive claims. Use middleware that extracts and verifies the JWT before routing, and ensure audience and issuer checks include the expected hostname or are omitted if not required. This prevents a request reaching an endpoint without proper authorization due to DNS misconfiguration.

Below is a concrete, secure Axum example that applies JWT validation as a top-level middleware, ensuring all routes are protected and hostname claims are verified against the intended service host:

use axum::{routing::get, Router, http::HeaderMap, extract::FromRequest, async_trait};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, TokenData};
use std::net::SocketAddr;
use tower_http::trace::TraceLayer;

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

struct JwtExtractor(pub TokenData);

#[async_trait]
impl FromRequest for JwtExtractor
where
    B: Send + Sync,
{
    type Rejection = (axum::http::StatusCode, String);

    async fn from_request(req: axum::http::Request, _state: &B) -> Result {
        let headers = req.headers();
        let token = headers.get("authorization")
            .and_then(|v| v.to_str().ok())
            .and_then(|s| s.strip_prefix("Bearer "))
            .ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing or malformed authorization header".to_string()))?;

        // Adjust expected_audience to your deployment host, e.g., "api.example.com"
        let expected_audience = std::env::var("EXPECTED_AUDIENCE").unwrap_or_else(|_| "api.example.com".to_string());
        let mut validation = Validation::new(Algorithm::HS256);
        validation.validate_aud = true;
        validation.set_audience(&[&expected_audience]);
        validation.issuer = vec!["https://auth.example.com".to_string()].into_iter().map(|s| jsonwebtoken::Issuer::new(s)).collect();

        let key = DecodingKey::from_secret("secret".as_ref());
        let token_data = decode::(token, &key, &validation)
            .map_err(|e| (axum::http::StatusCode::UNAUTHORIZED, format!("Invalid token: {}", e)))?;

        // Optional: enforce hostname alignment by checking aud claim matches the request host
        let request_host = req.uri().host().unwrap_or("").to_string();
        if let Some(ref aud) = token_data.claims.aud {
            if aud != &request_host {
                return Err((axum::http::StatusCode::FORBIDDEN, "Audience mismatch with request host".to_string()));
            }
        }

        Ok(JwtExtractor(token_data))
    }
}

async fn me_handler(JwtExtractor(token_data): JwtExtractor) -> String {
    format!("user: {}", token_data.claims.sub)
}

fn app() -> Router {
    Router::new()
        .route("/me", get(me_handler))
        .route("/health", get(|| async { "ok" }))
        .layer(TraceLayer::new_for_http())
}

#[tokio::main]
async fn main() {
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    println!("Listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app().into_make_service())
        .await
        .unwrap();
}

This example ensures JWT validation occurs for all incoming requests, validates the audience claim against the request host to mitigate host confusion, and rejects tokens with mismatched issuers. It aligns with OWASP API Security Top 10 authentication and authorization failures and helps prevent access via unintended endpoints, including those reached through dangling DNS records.

For teams using middleBrick, running a scan against this service will surface missing auth on routes, missing hostname validation, and other misconfigurations. If you have a Pro plan, continuous monitoring can detect regressions as routes or DNS change, and the GitHub Action can fail builds if a scan drops below your chosen threshold.

Frequently Asked Questions

How does middleBrick detect JWT issues related to hostname misconfigurations?
middleBrick tests unauthenticated endpoints and compares findings against your OpenAPI spec, flagging routes that lack required authentication and checks for missing hostname validation in JWT claims.
Can middleBrick prevent issues caused by dangling DNS records?
middleBrick detects and reports insecure routing and missing auth on exposed endpoints, helping you identify unintended surfaces that could be reached via dangling DNS records. It does not fix DNS or routing; it provides findings and remediation guidance.