Skip to main content

no-vulnerable

Disallow regular expressions that are potentially vulnerable to ReDoS (Regular Expression Denial of Service).

Targeted pattern scope

This rule checks:

  • /(...)/flags literals.
  • RegExp("...") and new RegExp("...", "flags") when both arguments are statically-known strings.

This rule intentionally skips dynamic patterns/flags it cannot resolve safely at lint time.

What this rule reports

This rule analyzes regular expression literals and statically-resolvable RegExp(...) constructor calls using recheck.

This rule reports patterns that recheck identifies as vulnerable with polynomial or exponential complexity.

Why this rule exists

Catastrophic backtracking can make an application spend excessive CPU time on crafted inputs. In server contexts, that can become an availability issue.

❌ Incorrect

const unsafe = /(a+)+$/;
const unsafe = RegExp("(a+)+$");
const unsafe = new RegExp("(a+)+$", "u");

✅ Correct

const safe = /^a+$/;
const source = getPatternFromConfig();
const maybeUnsafe = RegExp(source); // Dynamic value: intentionally not analyzed.

Behavior and migration notes

type Options = [
{
ignoreErrors?: boolean;
permittableComplexities?: Array<"polynomial" | "exponential">;
timeout?: number | null;
}?,
];

Default options

{
ignoreErrors: true,
permittableComplexities: [],
}

ignoreErrors

When true (default), analysis failures from recheck are ignored. When false, analysis failures are reported.

Analyzer failures include invalid regular expression syntax and backend startup errors from the recheck runtime. On Windows, this rule normalizes the temporary RECHECK_JAR and RECHECK_BIN values while invoking recheck so an upstream path-separator bug cannot make Java execute package.json instead of recheck.jar.

permittableComplexities

Allows selected vulnerable complexity classes to pass.

For example, to allow polynomial but still report exponential:

{
permittableComplexities: ["polynomial"],
}

Original plugin source: eslint-plugin-redos-detector.

ESLint flat config example

import etcMisc from "eslint-plugin-etc-misc";

export default [
{
plugins: { "etc-misc": etcMisc },
rules: {
"etc-misc/no-vulnerable": "error",
},
},
];

When not to use it

  • If your codebase never handles untrusted input with regexes.
  • If lint-time regex analysis cost is unacceptable for your workflow.
  • If you prefer running ReDoS scanning as a separate CI security step rather than as an ESLint rule.

Further reading