Auth Bypass in Axum with Basic Auth
Auth Bypass in Axum with Basic Auth — how this specific combination creates or exposes the vulnerability
Basic Authentication in HTTP transmits credentials as base64-encoded values without confidentiality guarantees. In Axum, developers often add a basic_auth layer using middleware or extractor patterns. If the implementation treats a missing or malformed Authorization header as a pass (for example, returning early or falling back to an unauthenticated route), an attacker can bypass intended access controls. A common mispattern is to decode the token but not validate its presence strictly, allowing an omitted header to proceed as an anonymous identity. This becomes an Auth Bypass when a route that should require a valid user is reachable without a correct Basic Auth credential.
Another bypass vector arises from inconsistent enforcement across route layers. For instance, an extractor may succeed for a subset of users while other handlers skip authorization checks, leading to horizontal privilege confusion. If routes are split across multiple modules and one omits the auth guard, a direct path exists for unauthenticated access to admin or sensitive endpoints. Because Basic Auth does not provide session semantics, tokens can be leaked in logs, browser history, or Referer headers, enabling credential replay across origins. When combined with weak transport protections, intercepted base64 strings can be trivially decoded, exposing static credentials.
In a black-box scan, such as one performed by middleBrick, these logic flaws are surfaced through unauthenticated endpoint probing combined with spec analysis. The OpenAPI/Swagger definition is resolved fully, including $ref chains, and runtime tests compare expected authentication requirements against actual responses. If endpoints return 200/success without a valid Authorization header where required, findings are raised with severity and remediation guidance. This testing approach maps to the OWASP API Top 10 (2023) A07:2023 — Identification and Authentication Failures and aligns with checks in the Authentication category.
Consider a scenario where an Axum service defines a guard that decodes credentials but does not enforce presence. An omitted header results in a default anonymous user, allowing access to administrative routes. In runtime probes, middleBrick validates that endpoints enforce authentication uniformly and flags deviations. Developers should treat Basic Auth as a transport-bound credential mechanism and enforce it consistently at every layer, ensuring no route silently accepts unauthenticated traffic.
Basic Auth-Specific Remediation in Axum — concrete code fixes
Secure Basic Auth in Axum requires strict validation of credentials on every route that requires protection. Always check the presence and correctness of the Authorization header, and never fall back to an anonymous identity. Use strong password hashing for credential storage and enforce HTTPS to prevent credential leakage. Below are concrete, working examples that demonstrate correct patterns.
Correct Basic Auth extractor with strict validation
use axum::async_trait;
use axum::extract::Request;
use axum::http::header;
use axum::middleware::Next;
use axum::response::Response;
use std::convert::Infallable;
use tower_http::auth::{Authorization, AuthError, BearerAuth, ParseAuthorization};
/// Strict Basic Auth extractor that rejects missing or malformed headers.
#[derive(Debug, Clone)]
pub struct BasicCredentials {
pub username: String,
pub password: String,
}
#[async_trait]
impl ParseAuthorization for BasicCredentials {
type Error = AuthError;
fn parse(&self, req: &Request) -> Result, Self::Error> {
let header = req.headers().get(header::AUTHORIZATION)
.ok_or(AuthError::Unauthorized {
www_authenticate: "Basic realm=\"secure\"".parse().unwrap(),
})?;
let header = header.to_str().map_err(|_| AuthError::Unauthorized {
www_authenticate: "Basic realm=\"secure\"".parse().unwrap(),
})?;
if !header.starts_with("Basic ") {
return Err(AuthError::Unauthorized {
www_authenticate: "Basic realm=\"secure\"".parse().unwrap(),
});
}
let token = &header[6..];
let decoded = general_purpose::STANDARD.decode(token)
.map_err(|_| AuthError::Unauthorized {
www_authenticate: "Basic realm=\"secure\"".parse().unwrap(),
})?;
let creds = String::from_utf8(decoded)
.map_err(|_| AuthError::Unauthorized {
www_authenticate: "Basic realm=\"secure\"".parse().unwrap(),
})?;
let mut parts = creds.splitn(2, ':');
let username = parts.next().ok_or(AuthError::Unauthorized {
www_authenticate: "Basic realm=\"secure\"".parse().unwrap(),
})?.to_string();
let password = parts.next().unwrap_or_default().to_string();
// Here you would verify username/password against a secure store
if username.is_empty() || password.is_empty() {
return Err(AuthError::Unauthorized {
www_authenticate: "Basic realm=\"secure\"".parse().unwrap(),
});
}
Ok(Authorization(BasicCredentials { username, password }))
}
}
/// A guard that enforces authentication.
#[async_trait]
impl FromRequest for BasicCredentials
where
S: Send + Sync,
{
type Rejection = (StatusCode, &'static str);
async fn from_request(req: Request, _state: &S) -> Result {
self.parse(&req).map(|a| a.into_inner())
.map_err(|e| match e {
AuthError::Unauthorized { .. } => (StatusCode::UNAUTHORIZED, "Unauthorized"),
AuthError::Forbidden => (StatusCode::FORBIDDEN, "Forbidden"),
})
}
}
/// Example protected route.
async fn admin_handler(creds: BasicCredentials) -> &'static str {
"Admin area"
}
/// Build your app with the auth guard on protected routes.
fn app() -> Router {
Router::new()
.route("/admin", get(admin_handler))
.route("/public", get(|| async { "public" }))
.layer(middleware::from_fn_with_state((), |_, request, next| async move {
// Apply selectively; here shown as global for clarity.
let _ = BasicCredentials::from_request(request, &()).await;
next.run(request).await
}))
}
Middleware-level enforcement to prevent bypass
Use middleware to ensure authentication checks are applied consistently and to avoid accidental omission in any route. The following middleware rejects requests without valid Basic Auth for protected paths.
use axum::async_trait;
use axum::extract::Request;
use axum::middleware::{self, Next};
use axum::http::StatusCode;
use axum::response::Response;
use std::convert::Infallable;
pub async fn basic_auth_middleware(
request: Request,
next: Next,
) -> Result {
let path = request.uri().path();
if path.starts_with("/admin") || path.starts_with("/secure") {
// Use the same strict extractor from above; simplified here.
let header = request.headers().get("authorization");
match header {
Some(h) if h.to_str().map(|s| s.starts_with("Basic ")).unwrap_or(false) => {
// Validate credentials; reject if invalid.
let _ = validate_basic_auth(h).await.map_err(|_| (StatusCode::UNAUTHORIZED, "Unauthorized"))?;
Ok(next.run(request).await)
}
_ => Err((StatusCode::UNAUTHORIZED, "Unauthorized")),
}
} else {
Ok(next.run(request).await)
}
}
async fn validate_basic_auth(header: &http::HeaderValue) -> Result<(), ()> {
// decode and verify credentials; return Ok(()) if valid
unimplemented!()
}
Mapping to compliance and scanning
These practices map to OWASP API Top 10 controls and support findings in the Authentication and Authorization categories. When using middleBrick’s scans, endpoints that lack consistent authentication guards will appear in findings with severity and remediation guidance. The GitHub Action can enforce a minimum score threshold, and the CLI allows you to scan from terminal with middlebrick scan <url>. Continuous monitoring plans in the Pro tier can schedule regular checks to detect regressions when routes or guards are modified.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |