Regex Dos in Feathersjs with Jwt Tokens
Regex Dos in Feathersjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Regex Denial-of-Service (Regex DoS) occurs when an attacker provides input that causes a regular expression to exhibit catastrophic backtracking, consuming excessive CPU time. In FeathersJS applications that use JWT tokens, this risk arises in two primary contexts: (1) validation and parsing of JWT-related input such as tokens in query parameters, headers, or payload fields; (2) custom hooks or services that apply regex patterns to strings that may include token values, claims, or identifiers.
FeathersJS does not inherently introduce regex vulnerabilities, but its flexibility allows developers to add hooks and services where unsafe patterns can be introduced. For example, a hook might validate an email claim in a JWT using a permissive regex like /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/. If an attacker can supply input that reaches this regex—such as a specially crafted email claim or a token-derived parameter—the pattern can be forced into exponential time due to nested quantifiers on overlapping character classes.
JWT tokens themselves are often long, structured strings composed of base64url-encoded segments. When regex patterns are applied to parts of a token (for instance, to validate a custom claim format or to extract values using capture groups), poorly designed expressions can cause catastrophic backtracking as the engine attempts many possible matching paths. Common triggers include patterns with nested quantifiers (e.g., /(a+)+$/) applied to strings derived from token payloads, or overly broad character classes combined with mandatory groups.
In a FeathersJS service, if an endpoint accepts a token or a token-derived identifier as part of the query or body, and server-side code runs regex checks on those values without constraints, the unauthenticated attack surface expands. Although FeathersJS typically relies on JWT verification middleware to authenticate requests, developer-defined hooks that process token contents or related strings can inadvertently introduce regex patterns susceptible to DoS. Because scans test the unauthenticated attack surface, an endpoint that echoes or processes token fields without strict input constraints can be probed for such behavior.
To illustrate, consider a hook that attempts to validate a custom claim format using an expensive pattern:
// Unsafe pattern in a FeathersJS hook
const validateClaim = (claim) => {
const pattern = /^([a-zA-Z0-9_\-\.]+)*@([a-zA-Z0-9_\-\.]+)$/; // Nested quantifiers
return pattern.test(claim);
};
An attacker can send a long string with repeated characters that forces exponential backtracking during regex execution, leading to resource exhaustion on the server. Effective remediation involves simplifying patterns, avoiding nested quantifiers, using atomic groups where supported, and applying length and structure constraints before regex evaluation.
Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on avoiding unsafe regex constructs and ensuring that any regex applied to token-related input is linear in complexity. Below are concrete, safe approaches and code examples for FeathersJS services and hooks.
1. Replace nested quantifiers with bounded patterns
Avoid patterns like ^([a-zA-Z0-9_\-\.]+)*@([a-zA-Z0-9_\-\.]+)$. Instead, use explicit bounds or simpler validation that does not rely on nested repetition. For email-like claims, prefer standard library validation or a tightly scoped regex.
// Safe: bounded pattern without nested quantifiers
const safeEmailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const isValid = safeEmailPattern.test(input);
2. Use length limits and early rejection
Before applying regex, enforce length constraints to prevent excessively long inputs from triggering pathological backtracking.
// FeatherJS hook example with guard checks
app.hooks.push({
before: async context => {
const { claim } = context.params.query;
if (typeof claim !== 'string' || claim.length > 200) {
throw new Error('Invalid claim');
}
const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!pattern.test(claim)) {
throw new Error('Claim format invalid');
}
return context;
}
});
3. Avoid regex for token validation; use structured parsing
When dealing with JWTs, validate claims using a JWT library rather than regex. For custom claims, decode the payload and validate types and ranges programmatically.
// Safe JWT claim validation without regex
const jwt = require('jsonwebtoken');
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAZXhhbXBsZSJ9.signature';
try {
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
if (typeof decoded.email !== 'string' || !decoded.email.includes('@')) {
throw new Error('Invalid email claim');
}
// Proceed safely
} catch (err) {
throw new Error('Invalid token');
}
4. Use atomic groups or possessive quantifiers where regex engine supports them
If regex is necessary, prefer atomic groups (e.g., (?>(pattern))) or possessive quantifiers (e.g., a++) to prevent backtracking. Note that JavaScript regex does not support possessive quantifiers, so rely on bounded quantifiers and non-capturing groups instead.
// Safer pattern using non-capturing groups and explicit bounds
const pattern = /^(?:[a-zA-Z0-9_\-\.]{1,64})*@(?:[a-zA-Z0-9_\-\.]{1,64})$/;
5. Centralize and audit regex usage
Review hooks and services for any regex processing of token-derived strings. Consolidate validation logic into shared utilities to ensure consistent safe patterns across the service.
// Shared validation utility
const validators = {
email: (value) => /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value),
};
module.exports = validators;
By combining bounded patterns, input length checks, and structured JWT decoding, FeathersJS applications can avoid regex-related DoS while still validating token-related data safely.
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 |