Xpath Injection in Axum with Basic Auth
Xpath Injection in Axum with Basic Auth
Xpath Injection occurs when untrusted data is concatenated into an XPath expression without proper sanitization or parameterization, allowing an attacker to alter the query logic. Axum, a web framework for Rust, does not provide built-in XPath utilities; if your application builds XPath strings manually—often to query an XML store behind a Basic Auth protected endpoint—the framework does not sanitize inputs for you.
When Basic Auth is used in Axum, credentials are typically validated before processing the request body or query parameters. A common pattern is to extract a username and password from the Authorization header and then use those values to construct an XPath selection over an XML document (for example, to look up user roles or permissions). If the username or another user-controlled value is directly interpolated into the XPath string, an attacker can supply payloads such as ' or '1'='1 to change the predicate logic. This can bypass intended access controls or extract sensitive XML nodes that would otherwise be restricted.
Consider a scenario where Axum uses a third-party XPath library to authorize a user against an XML-based identity store. A vulnerable handler might concatenate the provided username into an XPath expression like /users/user[username='$username' and password='$password']. An attacker authenticating with a crafted username like ' or //secret_password/text()=' can shift the predicate’s intent, potentially returning nodes outside the authorized scope. Because Basic Auth transmits credentials in base64-encoded form (not encryption), interception risks further amplify the impact of successful XPath Injection, especially if the XML data itself contains sensitive information.
To detect this risk with middleBrick, you can submit the endpoint URL (including the Basic Auth header) for a black-box scan. The tool runs 12 parallel security checks, including Authentication, Input Validation, and Property Authorization, and compares findings against the OpenAPI specification if available. The LLM/AI Security module additionally probes for system prompt leakage and output anomalies, which is relevant when XPath queries are used to influence AI-driven workflows.
middleBrick reports findings with severity levels and remediation guidance, helping you prioritize fixes such as parameterized XPath queries or strict input allow-listing. The CLI tool (middlebrick scan <url>) and Web Dashboard make it easy to track these issues over time, while the GitHub Action can enforce security thresholds in CI/CD pipelines.
Basic Auth-Specific Remediation in Axum
Remediation focuses on avoiding string concatenation when constructing XPath expressions and ensuring that authentication logic does not expose XML structure through error messages. Use parameterized XPath APIs when available, and treat all user input as untrusted, even after successful Basic Auth validation.
Below is a concrete Axum handler example that demonstrates secure handling of Basic Auth and safe XPath construction. It avoids interpolating credentials directly into query strings and uses a map-based parameter approach to simulate parameterized XPath behavior with a common Rust XML library.
use axum::{{
async_trait,
extract::{self, FromRequest},
http::HeaderValue,
response::IntoResponse,
routing::get,
Router,
}};
use base64::decode;
use serde::Deserialize;
use std::collections::HashMap;
// Simulated parameterized XPath helper (library-specific API may vary)
fn select_nodes(xml: &str, params: &HashMap<&str, &str;>) -> Vec<String> {
// In practice, use a library that supports variable binding,
// e.g., sxd-document with explicit variable resolution.
// This is a simplified placeholder.
let mut results = Vec::new();
if params.get("username").map_or(false, |u| u == "admin") {
results.push("admin_role".to_string());
}
results
}
async fn validate_credentials(
auth_header: extract::Header<HeaderValue>
) -> Result<(String, String), (axum::http::StatusCode, &'static str)> {
let header = auth_header
.0
.to_str()
.map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Invalid header"))?;
if !header.starts_with("Basic ") {
return Err((axum::http::StatusCode::UNAUTHORIZED, "Unsupported auth type"));
}
let encoded = &header[7..];
let decoded = decode(encoded)
.map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Invalid base64"))?;
let creds = String::from_utf8(decoded)
.map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Invalid UTF-8"))?;
let parts: Vec<&str> = creds.splitn(2, ':').collect();
if parts.len() != 2 {
return Err((axum::http::StatusCode::UNAUTHORIZED, "Invalid credentials format"));
}
Ok((parts[0].to_string(), parts[1].to_string()))
}
async fn user_handler(
(username, password) : extract::Query<HashMap<String, String>>,
auth: extract::Header<HeaderValue>
) -> impl IntoResponse {
let (user, pass) = match validate_credentials(auth).await {
Ok(creds) => creds,
Err((status, msg)) => return (status, msg).into_response(),
};
// Safe: using a parameter map instead of string interpolation
let mut params = HashMap::new();
params.insert("username", user.as_str());
params.insert("password", pass.as_str());
// Example XML document (in practice, load from a secure source)
let xml_data = r#"<users><user><username>admin</username><password>secret</password><role>admin_role</role></user></users>"#;
match select_nodes(xml_data, ¶ms) {
roles if !roles.is_empty() => (axum::http::StatusCode::OK, roles).into_response(),
_ => (axum::http::StatusCode::FORBIDDEN, "Access denied").into_response(),
}
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/user", get(user_handler));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
Key practices include avoiding XPath string concatenation with user input, validating and decoding Basic Auth credentials in a separate function, and returning generic error messages to prevent information leakage. If your XML library supports it, prefer APIs that accept variable bindings or compiled expressions. middleBrick scans can verify that no credentials are embedded in error payloads and that input validation aligns with the declared OpenAPI schema.