Regex Dos in Axum
How Regex DoS Manifests in Axum
Regular expression denial of service (ReDoS) in Axum applications typically occurs when route path parameters or request body fields are validated using vulnerable regex patterns. The problem becomes particularly acute in Axum due to its compile-time route extraction and strong typing system.
A common vulnerability pattern appears in Axum when using Path parameters with complex regex constraints. Consider this route definition:
use axum::routing::get;
use axum::extract::Path;
async fn get_user(Path((user_id, action)): Path<(String, String)>) {
// Process request
}
let app = axum::Router::new()
.route("/users/:user_id([a-zA-Z0-9]{1,20})/:action", get(get_user));
The regex [a-zA-Z0-9]{1,20} seems safe, but more complex patterns can cause catastrophic backtracking. An attacker can craft inputs that force the regex engine into exponential time complexity.
Another Axum-specific manifestation occurs with JSON body extraction. When using Json<T> extractor with custom validation:
use axum::extract::Json;
use serde::Deserialize;
#[derive(Deserialize)]
struct CreateUserRequest {
#[serde(deserialize_with = "validate_email")]
email: String,
// other fields
}
async fn create_user(Json(req): Json<CreateUserRequest>) {
// Process request
}
If validate_email uses a vulnerable regex pattern, an attacker can send a malicious JSON payload that triggers ReDoS during deserialization, blocking the worker thread.
The issue is compounded in Axum because route handlers are async functions that typically run on a Tokio runtime. A single ReDoS attack can block an entire worker thread, preventing it from processing other requests until the regex evaluation completes or times out.
Axum-Specific Detection
Detecting ReDoS vulnerabilities in Axum applications requires both static analysis and runtime scanning. For static analysis, examine all regex patterns used in:
- Route path parameters with regex constraints
- Custom deserialization with
#[serde(deserialize_with)] - Manual validation in
async fnhandlers - Middleware that processes request data
Axum's compile-time route extraction means regex patterns are embedded in the route definitions, making them easier to audit systematically. Use tools like cargo-audit or custom scripts to extract all regex patterns from your route definitions.
For runtime detection, middleBrick provides specialized scanning for Axum applications. The scanner tests your API endpoints with crafted inputs designed to trigger ReDoS conditions:
$ middlebrick scan https://api.example.com
✅ Authentication: A (no auth required)
⚠️ BOLA/IDOR: B (no auth checks found)
⚠️ Regex DoS: C (found potentially vulnerable patterns)
Detailed Findings:
- Route: /users/:id([a-z]+)
Issue: Vulnerable regex pattern detected
Severity: Medium
Recommendation: Use atomic grouping or limit input length
middleBrick's ReDoS detection specifically identifies patterns like nested quantifiers, overlapping alternatives, and unbounded repetitions that are common in Axum route definitions. The scanner generates attack payloads based on known ReDoS patterns and measures response times to identify exponential behavior.
For comprehensive security, integrate middleBrick into your CI/CD pipeline using the GitHub Action:
uses: middlebrick/middlebrick-action@v1
with:
url: http://localhost:3000
fail-on-severity: high
This ensures ReDoS vulnerabilities are caught before deployment to production.
Axum-Specific Remediation
Remediating ReDoS vulnerabilities in Axum requires a multi-layered approach. The most effective strategy combines input length limits, safe regex patterns, and timeout mechanisms.
First, implement input length validation at the route level using Axum's built-in extractors:
use axum::extract::{Path, Query};
use axum::http::StatusCode;
use axum::response::IntoResponse;
async fn safe_get_user(
Path((user_id, action)): Path<(String, String)>,
) -> Result<impl IntoResponse, StatusCode> {
// Validate input length before processing
if user_id.len() > 20 || action.len() > 20 {
return Err(StatusCode::BAD_REQUEST);
}
// Safe processing logic
Ok("user data")
}
Second, use atomic grouping and possessive quantifiers to prevent backtracking:
// Vulnerable pattern
let pattern = r#"[a-zA-Z0-9]+"#;
// Safer pattern with atomic grouping
let safe_pattern = r#"(?>([a-zA-Z0-9])+)ℕ"#;
Third, implement timeout middleware for regex-heavy operations:
use axum::middleware::from_fn;
use tokio::time::{timeout, Duration};
async fn regex_timeout_middleware(
mut req: axum::http::Request,
next: axum::middleware::Next,
) -> axum::http::Response {
let res = timeout(
Duration::from_millis(100),
next.run(req),
).await;
match res {
Ok(res) => res,
Err(_) => StatusCode::REQUEST_TIMEOUT.into_response(),
}
}
Fourth, use Axum's error handling to gracefully handle validation failures:
use axum::error_handling::HandleErrorLayer;
use axum::http::StatusCode;
let app = Router::new()
.route(...)
.layer(HandleErrorLayer::new(|error: std::io::Error, _req| {
StatusCode::INTERNAL_SERVER_ERROR.into_response()
}));
For JSON body validation, use safe parsing libraries and validate before deserialization:
use serde::Deserialize;
use serde_json::Value;
#[derive(Deserialize)]
struct CreateUserRequest {
email: String,
// other fields
}
async fn create_user_safe(
Json(raw): Json<Value>,
) -> Result<impl IntoResponse, StatusCode> {
// Validate JSON structure first
if !raw.is_object() {
return Err(StatusCode::BAD_REQUEST);
}
// Safe deserialization
let req = serde_json::from_value::(raw)
.map_err(|_| StatusCode::BAD_REQUEST)?;
Ok("user created")
}
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 can I test my Axum application for ReDoS vulnerabilities?
Are there any Rust crates that help prevent ReDoS in Axum applications?
fancy-regex provide safe regex operations with timeout support. The regex crate itself is generally safe for most patterns, but you should still avoid complex nested quantifiers. For input validation, consider using validator crate which provides pre-validated patterns. Always combine these with input length limits and timeout middleware in your Axum application.