Open Redirect in Axum with Mutual Tls
Open Redirect in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability
An open redirect occurs when an application redirects a user to an arbitrary URL supplied in attacker-controlled input. In Axum, this commonly maps to a handler that reads a next or redirect_to query parameter and passes it to redirect::temporary or similar. When mutual TLS (mTLS) is enforced, the server validates the client certificate before reaching the handler. This creates a false sense of strong authentication: operators assume that because only authorized clients can connect, the request is inherently safe. However, authorization (mTLS) and input validation are separate concerns. An authorized, mTLS-authenticated client can still supply a malicious URL. Because mTLS reduces the attack surface to trusted clients, developers may skip rigorous validation of parameters, inadvertently enabling an authenticated channel for phishing or host-header manipulation attacks.
During a middleBrick scan, the tool tests the unauthenticated attack surface by default. If mTLS is not correctly simulated or if a fallback path allows unauthenticated requests, the scanner can detect an open redirect via response status codes and location header analysis. Even with mTLS, if Axum does not validate the redirect target against an allowlist or ensure it is a relative path, the endpoint remains vulnerable. The risk is compounded when the mTLS client certificate is mapped to a user identity, and the redirect carries sensitive context, enabling targeted social engineering. MiddleBrick’s checks include analyzing how the framework handles location headers and whether input validation is applied after authentication.
Mutual Tls-Specific Remediation in Axum — concrete code fixes
Remediation centers on strict validation of redirect targets independent of transport security. Never trust parameters even when mTLS is enforced. Use a relative path or a strict allowlist of hosts for redirects. Below is a secure Axum handler that validates a redirect_to parameter against a configured base URL, combined with an example of enforcing mTLS with hyper-rustls.
use axum::{routing::get, Router, response::Redirect};
use std::net::SocketAddr;
/// Validate that the target is a relative path or matches allowed host.
fn is_safe_redirect_target(target: &str, allowed_host: &str) -> bool {
if let Ok(url) = url::Url::parse(target) {
// Only allow same-host redirects
url.host_str() == Some(allowed_host) && url.scheme() == "https"
} else {
// Relative paths are safe
target.starts_with('/')
}
}
async fn handler(
Query(params): Query>,
) -> Result {
let target = params.get("redirect_to").ok_or_else(|| (StatusCode::BAD_REQUEST, "missing redirect_to".into()))?;
const ALLOWED_HOST: &str = "app.example.com";
if is_safe_redirect_target(target, ALLOWED_HOST) {
Ok(Redirect::temporary(target))
} else {
Err((StatusCode::BAD_REQUEST, "invalid redirect target".into()))
}
}
// Example of building an Axum app with mTLS via hyper-rustls.
// Note: Certificate verification is configured at the Hyper/HTTPS layer.
#[tokio::main]
async fn main() {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let app = Router::new().route("/login", get(handler));
// hyper-rustls configuration would be applied here, ensuring client cert validation.
// This example focuses on routing logic; TLS setup is external to Axum.
tracing::info!(