Xss Cross Site Scripting in Actix with Mutual Tls
Xss Cross Site Scripting in Actix with Mutual Tls
Cross-site scripting (XSS) in Actix applications using mutual TLS (mTLS) can occur when untrusted data is reflected into HTML, JavaScript, or URLs without proper encoding, even though mTLS provides strong client authentication. mTLS ensures the client presenting the request possesses a valid certificate, but it does not sanitize or validate the content of the request itself. For example, an authenticated client may submit a payload such as <script>stealCookie(document.cookie)</script> in a JSON field or form input. If the Actix handler directly embeds this value into an HTML response without escaping, the browser will execute the script in the context of the victim’s session. This is a classic reflected XSS scenario, categorized under OWASP API Top 10 API1:2023 — Broken Object Level Authorization often because the developer conflates transport-layer identity with input safety.
Actix web does not automatically escape output; developers must explicitly encode data before rendering it in HTML, JavaScript, or attribute contexts. A typical vulnerable pattern is using web::Json to receive data and then inserting it into an HTML string via format macros or templates without sanitization. Even when mTLS verifies the client, an attacker who compromises a legitimate certificate (e.g., via stolen credentials or a misconfigured CA) can still exploit injection flaws. Additionally, if the API serves HTML fragments or JSON that are later rendered in a browser, improper escaping can lead to stored or DOM-based XSS. For instance, an attacker might store a malicious script in a profile field, which is later rendered in a dashboard without encoding.
Another angle involves the interplay between mTLS and OpenAPI spec-driven development. If the API specification does not define strict input schemas or encoding expectations, runtime findings from a scan may reveal injection points that bypass assumed trust. Tools like middleBrick can detect such inconsistencies by correlating spec definitions with runtime behavior, highlighting where user-supplied data enters the response chain without validation or encoding. This is especially important when APIs return data to JavaScript clients, where improper handling of quotes or newlines can break out of a string context and trigger script execution.
Mutual Tls-Specific Remediation in Actix
Remediation focuses on output encoding and strict input validation rather than relying on mTLS for data integrity. In Actix, always treat data from authenticated clients as untrusted. Use type-safe extractors and encode output based on context. Below are concrete examples demonstrating secure handling in an Actix application with mTLS configured.
1. Configure mTLS in Actix
Ensure your Actix server requires and validates client certificates. This example uses Rust’s native TLS support with rustls.
use actix_web::{web, App, HttpServer, Responder};
use actix_web::http::header::CONTENT_TYPE;
use actix_web::web::Data;
use actix_web_httpauth::extractors::bearer::BearerAuth;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
fn create_ssl_acceptor() -> SslAcceptor {
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
builder.set_ca_file("ca.pem").unwrap();
builder.set_verify(openssl::ssl::SslVerifyMode::PEER | openssl::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT);
builder.build()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let ssl = create_ssl_acceptor();
HttpServer::new(|| {
App::new()
.wrap(actix_web_httpauth::middleware::HttpAuthentication::basic(auth_middleware))
.route("/profile", web::get().to(profile_handler))
})
.bind_openssl("127.0.0.1:8443", ssl)?
.run()
.await
}
fn auth_middleware(req: &actix_web::HttpRequest, credentials: &str) -> bool {
// Validate client certificate details if needed, e.g., check common name
true
}
2. Encode Output to Prevent XSS
Use context-aware escaping. For HTML body content, the askama_escape crate is recommended. For JSON responses, ensure strings are properly serialized and not later injected into HTML without encoding.
use actix_web::web;
use askama::Template;
#[derive(Template)]
#[template(path = "profile.html")]
struct ProfileTemplate {
username: String,
}
async fn profile_handler(info: web::Json) -> impl Responder {
let username = askama_escape::Escape::new(info.username.clone()).to_string();
let template = ProfileTemplate { username };
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(template.render().unwrap())
}
3. Validate and Sanitize Input
Use Actix extractors with validation layers. For JSON, consider validator crate to enforce length and pattern constraints before processing.
use actix_web::web;
use serde::Deserialize;
use validator::Validate;
#[derive(Deserialize, Validate)]
struct ProfileInfo {
#[validate(length(min = 1, max = 50), regex = "^[a-zA-Z0-9_ ]*$")]
username: String,
}
async fn update_profile(info: web::Json<ProfileInfo>) -> impl Responder {
if let Err(e) = info.validate() {
return HttpResponse::BadRequest().body(e.to_string());
}
// Safe to use info.username
HttpResponse::Ok().finish()
}
These steps ensure that even with mTLS enforcing client identity, user-supplied data is properly handled, preventing XSS while maintaining strong transport-layer authentication.
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 |