Xss Cross Site Scripting in Axum
How XSS Cross-Site Scripting Manifests in Axum
Cross-Site Scripting (XSS) in Axum applications occurs when untrusted user input is rendered in HTML without proper sanitization. Axum's macro-based routing system and extractors make it easy to build APIs, but developers must be vigilant about output encoding when serving HTML content.
The most common XSS vectors in Axum include:
- Dynamic HTML generation: Using extractors like
Query,Path, orJsonto capture user input and directly embedding it in HTML templates - Template injection: Passing unsanitized data to template engines like Askama or Handlebars
- JavaScript injection: Including user-controlled data in
<script>tags, event handlers, or JSON responses - URL-based attacks: Reflected XSS through query parameters or path segments
Consider this vulnerable Axum route:
use axum::extract::Query;
use axum::response::Html;
async fn profile_page(Query(params): Query<HashMap<String, String>>) -> Html<String> {
let username = params.get("username").unwrap_or("Guest");
let html = format!("<h1>Welcome, {}</h1><p>Your profile</p>", username);
Html(html)
}
let app = Router::new().route("/profile", get(profile_page));If an attacker requests /profile?username=<script>alert(1)</script>, the script executes in victims' browsers. Axum itself doesn't provide automatic output encoding—developers must implement it manually or use safe templating.
Stored XSS can also occur when Axum APIs accept HTML content that gets persisted and later rendered. For example, a comment system API might accept HTML without sanitization:
async fn create_comment(Json(payload): Json<Comment>) -> impl Responder {
// payload.content is stored and later rendered without sanitization
store_comment(payload.content).await
}
#[derive(Deserialize)]
struct Comment {
content: String,
}The vulnerability here is accepting raw HTML from clients without validation or sanitization.
Axum-Specific Detection
Detecting XSS in Axum applications requires both static analysis and runtime scanning. Static analysis tools can identify dangerous patterns like direct string interpolation in HTML generation, but runtime scanning reveals actual vulnerabilities.
middleBrick's black-box scanning approach is particularly effective for Axum APIs. It tests unauthenticated endpoints by sending payloads that trigger XSS conditions and analyzes responses for script execution or HTML injection. The scanner checks:
- Reflected XSS in query parameters and path segments
- Stored XSS through API endpoints that accept HTML content
- DOM-based XSS by examining JSON responses for executable content
- Template injection vulnerabilities
For Axum applications, middleBrick scans endpoints like:
GET /api/profile?username=<script>alert(1)</script>
POST /api/comments { "content": "<img src=x onerror=alert(1)>" }
GET /api/data?callback=<script>alert(1)</script>The scanner evaluates whether responses contain the injected payloads in executable contexts. For template-based Axum applications using Askama, middleBrick can analyze template files alongside runtime behavior to identify unsafe data binding.
Manual detection techniques include:
use axum::extract::Query;
use axum::response::Html;
async fn test_xss(Query(params): Query<HashMap<String, String>>) -> Html<String> {
let test_payload = r#"<script>console.log('XSS test')</script>".to_string();
let html = format!("<div>{}</div>", params.get("test").unwrap_or(&test_payload));
Html(html)
}
// Test by requesting: /test?test=<img+src=x+onerror=alert(1)>middleBrick's API security scanning integrates with CI/CD pipelines via the GitHub Action, allowing you to automatically scan Axum endpoints before deployment. The Pro plan's continuous monitoring can periodically scan your API endpoints and alert you to new XSS vulnerabilities.
Axum-Specific Remediation
Remediating XSS in Axum requires a defense-in-depth approach. The most effective strategy combines output encoding, content security policies, and input validation.
For HTML generation, avoid direct string interpolation. Instead, use Axum's response types with proper encoding:
use axum::extract::Query;
use axum::response::Html;
use html_escape::encode_str;
async fn safe_profile(Query(params): Query<HashMap<String, String>>) -> Html<String> {
let username = params.get("username").unwrap_or("Guest");
let safe_username = encode_str(username);
let html = format!("<h1>Welcome, {}</h1>", safe_username);
Html(html)
}
// Cargo.toml dependency:
// html-escape = "0.2.11"For template-based applications using Askama, leverage the template engine's auto-escaping:
use axum::extract::Path;
use axum::response::Html;
use askama::Template;
#[derive(Template)]
#[template(path = "profile.html")]
struct ProfileTemplate {
username: String,
}
async fn profile(Path(username): Path<String>) -> Html<String> {
let template = ProfileTemplate { username };
Html(template.render().unwrap())
}
// profile.html uses auto-escaping by default:
// <h1>Welcome, {{ username }}</h1>For JSON APIs, ensure proper content-type headers and avoid JSON injection:
async fn get_user_profile(Path(id): Path<i32>) -> Json<UserProfile> {
let profile = get_profile_from_db(id).await;
Json(profile)
// Axum automatically sets Content-Type: application/json
// and handles proper JSON encoding
}
#[derive(Serialize)]
struct UserProfile {
username: String,
bio: String,
}
// Always validate and sanitize input data before processingImplement Content Security Policy headers to mitigate XSS impact:
use axum::http::HeaderValue;
use axum::response::{Html, IntoResponse};
async fn csp_protected_page() -> impl IntoResponse {
let csp = HeaderValue::from_static(
"default-src 'self'; script-src 'self' 'nonce-random123';"
);
(csp, Html("<script nonce='random123'>console.log('safe')</script>".to_string()))
}
// Add middleware to set CSP headers globally
use axum::middleware::Next;
use axum::response::Response;
async fn csp_middleware(
mut req: axum::http::Request<body::Body>,
next: Next<body::Body>,
) -> Result<Response, axum::http::Error> {
let mut res = next.run(req).await?;
res.headers_mut().insert(
"Content-Security-Policy",
HeaderValue::from_static(
"default-src 'self'; script-src 'self';"
),
);
Ok(res)
}
let app = Router::new()
.route("/", get(index))
.layer(axum::middleware::from_fn(csp_middleware));For input validation, use libraries like validator to sanitize user input before processing:
use validator::validate_email;
async fn register_user(Json(payload): Json<RegisterRequest>) -> impl Responder {
if !validate_email(&payload.email) {
return Json(json!({ "error": "Invalid email format" }));
}
// Sanitize other fields
let safe_username = sanitize_html(&payload.username);
create_user(safe_username, payload.email).await
}
#[derive(Deserialize)]
struct RegisterRequest {
username: String,
email: String,
}middleBrick's Pro plan includes continuous monitoring that can scan your Axum API endpoints on a schedule, alerting you to XSS vulnerabilities before they reach production. The GitHub Action integration allows you to fail CI builds if XSS risks are detected in your API endpoints.
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 |
Frequently Asked Questions
How does middleBrick detect XSS vulnerabilities in Axum applications?
Can middleBrick scan my Axum API during development?
middlebrick scan http://localhost:3000. The GitHub Action integrates with your CI/CD pipeline to scan staging APIs before deployment. The Pro plan includes continuous monitoring that can scan your Axum endpoints on a configurable schedule and alert you to new XSS vulnerabilities.