Regex Dos in Actix with Jwt Tokens
Regex Dos in Actix with Jwt Tokens — how this specific combination creates or exposes the vulnerability
A Regular Expression Denial of Service (Regex DoS) occurs when an attacker provides input that causes a regular expression engine to exhibit catastrophic backtracking, consuming excessive CPU time. In Actix web applications that validate JWT tokens in request handling code, this typically arises when a developer embeds a permissive or complex regex to validate parts of a token—such as the JWT ID (jti), issuer (iss), or subject (sub)—and the regex is applied to untrusted data without safeguards.
Consider an Actix handler that uses a Rust regex to enforce a custom format on a JWT-related header or claim. If the pattern includes nested quantifiers (e.g., (a+)+) and is applied to attacker-controlled strings, a maliciously crafted token can force the regex engine into exponential backtracking. Because Actix applications often process many concurrent requests, this can lead to high CPU utilization and thread starvation, degrading service for all users. The vulnerability is not in JWT parsing itself, but in the misuse of regular expressions on inputs that should be validated with simpler, linear-time checks.
In practice, a vulnerable pattern might appear in middleware that inspects a bearer token or a custom claim before the JWT is decoded. For example, a developer might attempt to restrict a kid (key ID) to alphanumeric characters with a pattern like ^[a-zA-Z0-9]{1,20}$, but inadvertently introduce a subtle flaw—such as optional groups or repeated wildcards—that turns a benign-looking regex into a backtracking trap when given a long string of repeating characters. Because the regex operates on untrusted data from the Authorization header, the attack surface is direct and requires no authentication, making it an attractive vector for resource exhaustion.
Because middleBrick scans unauthenticated endpoints and includes checks such as Input Validation and Unsafe Consumption, it can surface patterns where regex-based validation is applied to JWT-related inputs. Findings highlight the risk and provide remediation guidance, emphasizing that validation of tokens should rely on structured parsing and bounded string operations rather than complex regular expressions.
Jwt Tokens-Specific Remediation in Actix — concrete code fixes
To prevent Regex DoS when working with JWT tokens in Actix, avoid using complex or unbounded regex patterns to validate structured token metadata. Instead, use purpose-built JWT libraries that parse tokens without regex, and apply simple, bounded checks on specific fields when necessary.
Below is a safe approach in Actix using the jsonwebtoken crate for decoding and validation, with minimal string checks that avoid catastrophic backtracking:
use actix_web::{dev::ServiceRequest, Error, HttpRequest};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use std::time::SystemTime;
async fn validate_jwt_token(req: &ServiceRequest) -> Result {
// Extract Authorization header safely
let auth_header = match req.headers().get("Authorization") {
Some(h) => h.to_str().map_err(|_| actix_web::error::ErrorBadRequest("Invalid header"))?,
None => return Ok(false),
};
// Ensure it's a bearer token with bounded prefix check (linear time)
if !auth_header.starts_with("Bearer ") {
return Ok(false);
}
let token = &auth_header[7..];
// Avoid regex; enforce length bounds to prevent abuse
if token.len() < 10 || token.len() > 512 {
return Ok(false);
}
// Decode and validate using the JWT library (no regex on claims)
let decoding_key = DecodingKey::from_secret("your_secret".as_ref());
let mut validation = Validation::new(Algorithm::HS256);
validation.validate_exp = true;
validation.validate_nbf = true;
match decode::(token, &decoding_key, &validation) {
Ok(token_data) => {
// Apply simple, bounded checks on specific claims if needed
if let Some(iss) = token_data.claims.get("iss") {
if let Some(iss_str) = iss.as_str() {
// Bounded length check instead of regex
if iss_str.len() > 256 {
return Ok(false);
}
// Optionally allowlist known issuers without regex
if iss_str != "https://auth.example.com" {
return Ok(false);
}
} else {
return Ok(false);
}
}
Ok(true)
}
Err(_) => Ok(false),
}
}
If you must use regex for a narrow purpose (for example, validating an alphanumeric kid), ensure it is simple, anchored, and length-bounded:
// Safe: linear-time pattern with bounded length and no nested quantifiers
let kid_pattern = regex::Regex::new(r"^[A-Za-z0-9\-_]{1,32}$").expect("Valid regex");
if let Some(kid) = header_map.get("kid") {
if !kid_pattern.is_match(kid) {
return Err("Invalid key ID");
}
}
These practices align with guidance that middleBrick provides in its findings: prefer structured parsing and bounded checks over complex patterns, especially for high-risk inputs like JWT tokens. For teams using the Pro plan, continuous monitoring can flag new endpoints where regex-based validation is detected, enabling timely remediation before an exposure is exploited.
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 |