Regex Dos in Axum with Firestore
Regex Dos in Axum with Firestore — how this specific combination creates or exposes the vulnerability
A Regex DoS occurs when an attacker provides a malicious regular expression or input that causes exponential backtracking, leading to high CPU usage and service degradation. In Axum, this risk is elevated when route or query parameters are validated using complex or poorly constructed regex patterns and the validated values are later used to query Firestore. Firestore queries often rely on string-based filters, and if those strings originate from user-controlled regex matches, an attacker can craft inputs that force both the regex engine and Firestore query processing to consume excessive resources.
Consider an Axum handler that uses a regex to validate a document_id path parameter before using it in a Firestore get request:
use axum::{routing::get, Router};
use regex::Regex;
use firestore::FirestoreDb;
async fn get_document(
Path(id): Path,
db: Extension<FirestoreDb>,
) -> Result<impl IntoResponse, (StatusCode, String)> {
let re = Regex::new(r"^(a+)+$").unwrap(); // Dangerous regex
if re.is_match(&id) {
let doc = db.get_document(&id).await.map_err(|e| {
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
})?;
Ok(Json(doc))
} else {
Err((StatusCode::BAD_REQUEST, "Invalid ID"[..]))
}
}
The regex (a+)+$ is vulnerable to catastrophic backtracking when given an input like aaaa...aab. Even though the regex itself does not directly interact with Firestore, the CPU time spent evaluating it can block the Axum runtime. If the id passes the regex check, the same string is passed to Firestore. An attacker could exploit this by sending many requests with crafted IDs that cause long-running regex evaluations, indirectly amplifying load on the Firestore client and the overall service. The vulnerability is not in Firestore itself but in how user input bridges regex validation and Firestore operations.
Another scenario involves query parameters used to filter Firestore results. For example, an endpoint might accept a name parameter and apply a regex-based filter in application logic before issuing a Firestore query:
async fn search_users(
Query(params): Query<SearchParams>,
db: Extension<FirestoreDb>,
) -> Result<Json<Vec<User>>, (StatusCode, String)> {
let pattern = params.filter.unwrap_or_default();
// Complex regex built from user input
let re = Regex::new(&format!(r"^{}$", pattern)).map_err(|_| {
(StatusCode::BAD_REQUEST, "Invalid regex pattern".to_string())
})?;
let users = db.collection("users").get().await.map_err(|e| {
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
})?;
let filtered: Vec<User> = users.into_iter()
.filter(|u| re.is_match(&u.name))
.collect();
Ok(Json(filtered))
}
If the pattern comes from an untrusted source and is embedded into a regex without sanitization, an attacker can submit patterns designed to cause catastrophic backtracking. The CPU cost of evaluating these regexes can exhaust thread pools in Axum, leading to request queuing and timeouts. Although Firestore handles the data retrieval, the application-layer regex bottleneck becomes the denial-of-service vector.
MiddleBrick can detect such risks by scanning the API surface and identifying endpoints where user input influences regex patterns that interact with backend services like Firestore. Its findings include severity ratings and remediation guidance to help developers avoid these pitfalls.
Firestore-Specific Remediation in Axum — concrete code fixes
To mitigate Regex DoS in Axum when working with Firestore, avoid using complex or user-controlled regex patterns for validation and filtering. Instead, use simple, safe validation and ensure Firestore queries are constructed safely.
1. Replace vulnerable regex with strict allowlists
For document IDs, use a predictable format (e.g., UUID or numeric IDs) and validate with a simple pattern or direct parsing:
use axum::{routing::get, Router};
use firestore::FirestoreDb;
use uuid::Uuid;
async fn get_document(
Path(id): Path,
db: Extension<FirestoreDb>,
) -> Result<impl IntoResponse, (StatusCode, String)> {
// Validate UUID format without complex regex
let uuid = Uuid::parse_str(&id).map_err(|_| {
(StatusCode::BAD_REQUEST, "Invalid document ID".to_string())
})?;
let doc = db.get_document(&id.to_string()).await.map_err(|e| {
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
})?;
Ok(Json(doc))
}
This approach removes catastrophic backtracking risk entirely and ensures only valid document identifiers are passed to Firestore.
2. Avoid building regex from user input
If filtering by fields like email or username is required, use direct string comparisons or Firestore’s built-in filters instead of dynamically compiled regex:
async fn search_users(
Query(params): Query<SearchParams>,
db: Extension<FirestoreDb>,
) -> Result<Json<Vec<User>>, (StatusCode, String)> {
let name_prefix = params.name_prefix.ok_or_else(|| {
(StatusCode::BAD_REQUEST, "Missing name_prefix".to_string())
})?;
// Use Firestore range or equality queries instead of regex
let users = db.collection("users")
.filter("name", ">=", &name_prefix)
.filter("name", "<", &format!("{}{}", name_prefix, char::MAX))
.get()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(users))
}
This removes regex entirely and leverages Firestore’s native query capabilities, which are efficient and safe from ReDoS.
3. Use regex with timeouts and size limits
If regex validation is unavoidable, use a crate that supports timeouts (e.g., regex-automata with explicit DFA configurations) and enforce strict limits on input length:
use regex::Regex;
use std::time::Duration;
fn safe_regex() -> Result<Regex, &'static str> {
// Only allow simple patterns
let re = Regex::new(r"^[a-zA-Z0-9_-]{1,64}$").map_err(|_| "Invalid pattern")?;
Ok(re)
}
async fn validate_id(id: &str) -> bool {
if id.len() > 128 {
return false;
}
match safe_regex() {
Ok(re) => re.is_match(id),
Err(_) => false,
}
}
By constraining the regex pattern and input length, you reduce the risk of catastrophic backtracking and resource exhaustion.
MiddleBrick’s scans can help identify endpoints that still use unsafe regex patterns or expose Firestore queries to user-controlled inputs, providing prioritized findings with remediation guidance.
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 |