Bad Regex Syntax
ID |
javascript.bad_regex_syntax |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
reliability |
Description
Reports a regular expression whose pattern is not valid JavaScript regex syntax, written either as
a regex literal or as new RegExp("…") with a string-literal pattern. An invalid pattern throws
SyntaxError as soon as the expression is evaluated, so the code path that carries it is dead on
arrival.
Only shapes that are errors in every JavaScript mode are reported:
-
an unbalanced group or character class —
(unclosed,closed),[abc -
a quantifier with no atom to repeat —
abc,a* -
quantifier bounds in the wrong order —
a{3,1} -
a possessive quantifier —
a++,a*+; JavaScript has no such form -
an out-of-order character-class range —
[z-a] -
a pattern ending in a dangling backslash
-
the unscoped inline-flag group
(?i), which other regex dialects accept and JavaScript rejects
One further family is decided from the flags. With the u or v flag the Annex B
web-compatibility extensions are switched off, and an identity escape such as \A, \z or \G —
a plain letter match in a flagless pattern — becomes a syntax error.
Rationale
const opening = new RegExp("(unclosed"); // SyntaxError: Unterminated group
const bounded = new RegExp("a{3,1}"); // SyntaxError: numbers out of order in {} quantifier
const folded = new RegExp("(?i)abc"); // SyntaxError: Invalid group
const greedy = /\d++/; // SyntaxError: Nothing to repeat
const anchor = new RegExp("\\A", "u"); // SyntaxError: Invalid escape
A pattern written as a literal fails when the script is parsed; a pattern handed to RegExp fails
when the constructor runs, which is often inside a rarely taken branch — a validation helper, an
error formatter, a feature flag. The failure then arrives in production as a thrown SyntaxError
from code that looked reviewed and tested.
The unscoped (?i) group and the \A / \z anchors are the classic arrivals from a Java, .NET or
Python pattern that was copied across. Without the u flag \A is not an error at all: it quietly
matches the letter A, so the pattern keeps working and matches the wrong input.
Remediation
Fix the pattern. Close what it opens, give every quantifier an atom, and translate the constructs the dialect does not have:
const opening = new RegExp("(closed)");
const bounded = new RegExp("a{1,3}");
const folded = new RegExp("abc", "i"); // flags belong in the flags argument
const greedy = /\d+/;
const anchor = new RegExp("^", "u"); // ^ with the m flag off is the start of input
Where the pattern is genuinely built at run time, wrap the construction in try/catch so a bad
input string is rejected rather than crashing the caller.