HIGH ssrf server sideaxumbasic auth

Ssrf Server Side in Axum with Basic Auth

Ssrf Server Side in Axum with Basic Auth — how this specific combination creates or exposes the vulnerability

Server Side Request Forgery (SSRF) in an Axum service that uses HTTP Basic Authentication can occur when user-controlled input is used to construct outbound HTTP requests without adequate validation or network segregation. Axum is a Rust web framework that relies on typed extractors and middleware to manage request data and authentication. If an endpoint accepts a URL from the client and forwards it—often to satisfy business logic such as webhook calls, proxy-like behavior, or integration with internal services—it can inadvertently allow an attacker to direct the server to internal or unexpected endpoints.

Basic Authentication introduces a credential exchange that can be misused in this flow. When credentials are passed via the Authorization header, they may be reused by the server when initiating outbound requests. If the application does not carefully separate user input from internal routing logic, an attacker can supply a malicious URL pointing to internal services (e.g., http://127.0.0.1:8080/admin or a metadata service at http://169.254.169.254) and have the server authenticate and forward requests using the provided or defaulted credentials. This can lead to internal service enumeration, unauthorized access to administrative interfaces, or exfiltration of sensitive data from internal endpoints.

The combination is risky because Basic Auth credentials are often static or long-lived compared to token-based approaches, and they may be reused across multiple outbound calls. If the Axum handler does not validate the target host, enforce a strict allowlist, or remove sensitive headers before forwarding, SSRF becomes feasible. Runtime findings from scans can detect whether outbound requests initiated by the service reach unexpected internal addresses or metadata services, highlighting SSRF in the context of authenticated flows.

To illustrate, consider an endpoint that accepts a url query parameter and forwards a request with Basic Auth. Without proper controls, an attacker can supply http://169.254.169.254/latest/meta-data/ as the target, causing the server to make authenticated requests to the cloud metadata service.

// Example Axum handler with potential SSRF when forwarding user-supplied URLs
use axum::{
    extract::Query, http::Request, routing::get, Router,
    body::Body, http::header, middleware::from_fn_with_state,
};
use hyper::Client;
use std::net::SocketAddr;

#[derive(serde::Deserialize)]
struct ForwardParams {
    url: String,
}

async fn handler(
    Query(params): Query,
) -> Result {
    let client = Client::new();
    let req = Request::builder()
        .method("GET")
        .uri(params.url)
        .header(header::AUTHORIZATION, "Basic dXNlcjpwYXNz") // reused credentials
        .body(Body::empty())
        .map_err(|e| (http::StatusCode::BAD_REQUEST, e.to_string()))?;

    let response = client.request(req).await.map_err(|e| (http::StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
    let status = response.status();
    Ok(format!("Response status: {}", status))
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/forward", get(handler));
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap();
}

Basic Auth-Specific Remediation in Axum — concrete code fixes

Remediation focuses on preventing the server from blindly trusting user input for URLs and ensuring that credentials are not inadvertently reused for arbitrary destinations. First, avoid forwarding user-supplied URLs entirely; if forwarding is required, use a strict allowlist of permitted hosts and paths. Second, do not reuse Basic Auth credentials extracted from incoming requests for outbound calls. Instead, use a dedicated service identity or token that is scoped to the required destination and managed securely.

When you must perform outbound requests, construct the request server-side using safe components and avoid passing attacker-controlled values into the request target. Validate and sanitize any user input rigorously, and remove or avoid forwarding sensitive headers that may be present in the original request.

Below are concrete Axum code examples demonstrating safer patterns. The first example shows a handler that does not forward user URLs and instead calls a predefined internal service, using a fixed credential source rather than reusing client-provided Basic Auth data.

// Safe Axum handler: no user URL forwarding, fixed credentials for outbound calls
use axum::{
    extract::Extension, http::Request, routing::get, Router,
    body::Body, http::header, response::IntoResponse,
};
use hyper::Client;
use std::net::SocketAddr;

struct AppState {
    outbound_client: Client,
    // In practice, load credentials from a secure configuration or vault
    outbound_auth: String,
}

async fn safe_handler(
    Extension(state): Extension>,
) -> impl IntoResponse {
    let req = Request::builder()
        .method("GET")
        .uri("https://internal.service.local/health")
        .header(header::AUTHORIZATION, state.outbound_auth.clone())
        .body(Body::empty())
        .unwrap();

    let response = state.outbound_client.request(req).await;
    match response {
        Ok(resp) => format!("Health check status: {}", resp.status()),
        Err(e) => (http::StatusCode::BAD_GATEWAY, format!("Failed: {}", e)).into_response(),
    }
}

#[tokio::main]
async fn main() {
    let state = std::sync::Arc::new(AppState {
        outbound_client: Client::new(),
        outbound_auth: "Basic serviceAccountToken".to_string(),
    });

    let app = Router::new()
        .route("/health-check", get(safe_handler))
        .layer(axum::middleware::from_fn_with_state(
            state.clone(),
            |Extension(state), req, next| async move {
                // Example middleware: enforce host allowlist if URL reconstruction is needed
                async move { Ok(next.run(req).await) }
            },
        ))
        .with_state(state);

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap();
}

The second example demonstrates validating a user-supplied URL against an allowlist before any processing, ensuring that only known-internal endpoints are targeted and that credentials are not reused from the incoming request.

// Axum handler with host allowlist validation
use axum::{
    extract::Query, http::Request, routing::get, Router,
    body::Body, http::header, response::IntoResponse,
};
use hyper::Client;
use url::Url;
use std::net::SocketAddr;

#[derive(serde::Deserialize)]
struct ForwardParams {
    url: String,
}

fn is_allowed_host(uri: &str) -> bool {
    match Url::parse(uri) {
        Ok(parsed) => {
            let host = parsed.host_str().unwrap_or("");
            // Allowlist internal services only
            ["internal.service.local", "127.0.0.1", "10.0.0.2"].contains(&host)
        }
        Err(_) => false,
    }
}

async fn validated_handler(
    Query(params): Query,
) -> Result {
    if !is_allowed_host(¶ms.url) {
        return Err((http::StatusCode::BAD_REQUEST, "Host not allowed".into()));
    }

    let client = Client::new();
    // Build request without reusing incoming Authorization header
    let req = Request::builder()
        .method("GET")
        .uri(params.url)
        .header(header::USER_AGENT, "middleBrick-Scanner/1.0")
        .body(Body::empty())
        .map_err(|e| (http::StatusCode::BAD_REQUEST, e.to_string()))?;

    let response = client.request(req).await.map_err(|e| (http::StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
    let status = response.status();
    Ok(format!("Response status: {}", status))
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/forward-safe", get(validated_handler));
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap();
}

Frequently Asked Questions

Can middleBrick detect SSRF in Axum services that use Basic Auth?
Yes, middleBrick scans unauthenticated attack surfaces and can identify SSRF by observing whether outbound requests reach unexpected internal endpoints, including metadata services, even when Basic Auth headers are present.
Does middleBrick fix SSRF findings in Axum applications?
middleBrick detects and reports findings with remediation guidance; it does not fix, patch, block, or remediate. Developers should implement host allowlists, avoid credential reuse, and validate user input based on the provided guidance.