Xss Cross Site Scripting in Actix with Basic Auth
Xss Cross Site Scripting in Actix with Basic Auth — how this specific combination creates or exposes the vulnerability
Cross-site scripting (XSS) in Actix applications that use HTTP Basic Authentication can arise when user-controlled data is reflected into HTML, JavaScript, or CSS without proper encoding, and when authentication state is handled via non-secure channels. Basic Auth credentials are transmitted in the Authorization header as a base64-encoded string; this mechanism does not encrypt the payload, so credentials are easily decoded if intercepted. If an Actix endpoint embeds values from headers, query parameters, or JSON bodies directly into a response without context-aware escaping, an attacker may supply a token like <script>steal(document.cookie)</script> as a username or within a parameter that is later rendered in a browser. Because Basic Auth is often used for simple APIs consumed by browsers or intermediary clients, reflected values from these inputs can be stored or echoed into HTML pages, enabling stored or reflected XSS. The risk is amplified when the API also serves HTML fragments or JSON responses consumed by client-side JavaScript that do not enforce strict Content Security Policy (CSP). An attacker may leverage a compromised or guessed Basic Auth token to inject malicious payloads into authenticated sessions, leveraging the trust placed in the Authorization header to bypass same-origin checks. In an Actix-based service, if route handlers deserialize headers or form data into models and directly serialize them into templates or JSON, the framework’s default behavior does not automatically neutralize script execution contexts. This combination of permissive data reflection and weak encoding creates exploitable XSS conditions, especially when inputs are not validated against type and length, and when the API’s OpenAPI spec incorrectly marks such fields as safe without runtime sanitization.
Basic Auth-Specific Remediation in Actix — concrete code fixes
Remediation focuses on preventing reflected input from being interpreted as executable code and on protecting credentials in transit and in logs. Always treat inputs as untrusted, encode data for the correct context (HTML, JS, CSS, URL), and avoid reflecting authentication-derived values in responses. Below are concrete Actix examples that demonstrate secure handling.
1. Avoid echoing Basic Auth credentials in responses
Never include the Authorization header value or derived usernames in HTML or JSON responses. Instead, use server-side session identifiers or opaque tokens.
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use actix_web::http::header::HeaderValue;
use actix_web::dev::ServiceRequest;
use actix_web::error::ErrorUnauthorized;
async fn handler(req: ServiceRequest) -> actix_web::Result {
// Extract and validate credentials without echoing them back
if let Some(auth_header) = req.headers().get("Authorization") {
if let Ok(auth_str) = auth_header.to_str() {
if auth_str.starts_with("Basic ") {
// Decode and validate credentials (example only; use a proper validator)
let token = auth_str.trim_start_matches("Basic ");
// Perform validation, e.g., check against a secure store
if is_valid_token(token).await {
return Ok(HttpResponse::Ok().json(serde_json::json!({ "status": "authenticated" })));
}
}
}
}
Err(ErrorUnauthorized("Invalid credentials"))
}
async fn is_valid_token(_token: &str) -> bool {
// Replace with secure validation logic
true
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/api/secure", web::get().to(handler))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
2. Encode all user-controlled data before rendering
If your Actix service returns HTML or JSON that incorporates user data, apply context-specific escaping. For HTML body content, use the askama_escape feature or manually encode characters. For JSON, ensure serialization libraries escape special characters.
use actix_web::web;
use askama::Template;
#[derive(Template)]
#[template(path = "user_profile.html")]
struct ProfileTemplate {
username: String,
}
async fn profile(data: web::Query impl Responder {
let raw_username = data.get("username").cloned().unwrap_or_default();
// Encode for HTML context
let safe_username = html_escape::encode_text(&raw_username).to_string();
let template = ProfileTemplate { username: safe_username };
HttpResponse::Ok().content_type("text/html").body(template.render().unwrap())
}
3. Secure transport and header handling
Always serve over HTTPS to protect Basic Auth credentials in transit. Do not log Authorization headers, and enforce strict CSP headers to mitigate impact of any potential XSS.
use actix_web::middle Logger;
use actix_web::http::header::{HeaderValue, CONTENT_SECURITY_POLICY};
// In App configuration
App::new()
.wrap(Logger::default())
.wrap_fn(|req, srv| {
let mut resp = srv.call(req).into_future();
async move {
let (r, pl) = resp.try_split()?;
let mut res = HttpResponse::build(r.status());
res.insert_header((CONTENT_SECURITY_POLICY, HeaderValue::from_static("default-src 'self'")));
res.finish(pl.into_future().map(|_| (r, pl)))
}
})Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |