Description
Letting external input determine a regular expression pattern in TypeScript or JavaScript can allow an attacker to submit a pattern with excessive execution time, causing denial of service.
Potential impact
- Long occupation of the event loop can delay legitimate requests.
- High CPU usage may destabilize application instances.
Remediation
- Prefer reviewed regular expression literals or constants.
- If dynamic selection is necessary, use an allow-list rather than interpreting user input as pattern syntax.
- Avoid nested repetition and ambiguous alternatives that can increase execution time.
Examples
Before
typescript
function search(value: string, pattern: string) {
return new RegExp(pattern).test(value);
}
After
typescript
const allowedPatterns = new Map([
["username", /^[a-z0-9_]{3,32}$/i],
["ticket", /^TICKET-\d{4,10}$/],
]);
function search(value: string, patternName: string) {
const pattern = allowedPatterns.get(patternName);
if (!pattern) {
throw new Error("Unsupported pattern");
}
return pattern.test(value);
}
Explanation:
- Before: A caller-supplied string is interpreted directly as a regular expression pattern.
- After: A name selects a reviewed fixed pattern; unknown names are rejected.