safe-regex

Detects regular expressions prone to catastrophic backtracking (ReDoS) using AST-based star-height analysis.

Library
npm
v2.1.1
194stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
33/100Needs Attention
Development Activity0
Maintenance0
Community52
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
61/100Good
Architecture65
Code Quality68
Innovation55
Learning Curve55

safe-regex is a small, focused npm library that checks whether a regular expression is safe from catastrophic (exponential-time) backtracking before it ever runs against untrusted input. Rather than pattern-matching against a blocklist of “known bad” regex shapes, it parses the target regex into an AST with the regexp-tree package and measures its structural “star height” — how deeply repetition operators (*, +, {n,m}) are nested inside one another — flagging anything with a star height greater than one, or with more repetition operators than a configurable limit (25 by default).

The library exposes a single function, safeRegex(re, opts), that accepts either a RegExp object or a string and returns a boolean. Internally it delegates to a small family of pluggable Analyzer subclasses (currently just one, HeuristicAnalyzer) so additional detection strategies can be added later without changing the public API. A companion CLI (bin/cli.js) wraps the same check for batch analysis of JSON-described patterns, but the primary integration path is require('safe-regex') inside application code — for example, rejecting user-supplied search patterns before compiling them into a live RegExp.

The README is unusually candid about the tool’s limits: it documents specific known false positives (linear-time regexes it still flags, like (ab*)+) and false negatives (disjunction-driven blowups it misses, like (a|a)*), and points users toward the author’s related vuln-regex-detector project for more rigorous analysis. That transparency, plus a Jest test suite enforcing 100% coverage across a wide range of regex syntax, makes it a well-scoped first line of defense against ReDoS rather than a complete solution.

What You Get

  • A single safeRegex(re, opts) function that returns true/false for whether a RegExp or regex string is safe from catastrophic backtracking
  • AST-based star-height analysis via regexp-tree, instead of a brittle blocklist of known-bad patterns
  • A configurable opts.limit for the maximum number of repetition operators allowed (default 25)
  • Fail-safe behavior — invalid, unparseable, or non-regex input is treated as unsafe rather than throwing
  • A bin/cli.js command-line tool for batch-checking JSON-described patterns outside of application code
  • A documented, extensible Analyzer base class so additional detection heuristics can be added without changing the public API

Common Use Cases

  • Validating user-supplied search or filter patterns before compiling them into a live RegExp in a web app
  • Screening regex patterns accepted from configuration files, admin panels, or plugin systems where the source isn’t fully trusted
  • Adding an automated guard in CI or a linter step that rejects newly introduced regexes with dangerous nesting
  • Batch-auditing an existing codebase’s regex literals for catastrophic-backtracking risk via the CLI

Under The Hood

Architecture The library is a thin, layered design: index.js exposes the single public entry point safeRegex(re, opts), which builds an Args object (the parsed RegExp plus AnalyzerOptions) and hands it to every analyzer registered in analyzer-family.js — currently just HeuristicAnalyzer — OR-ing their isVulnerable() results together so any single analyzer flagging a pattern is enough to mark it unsafe. Each analyzer extends the abstract Analyzer base class defined in analyzer.js (isVulnerable() / genAttackString()), so new detection strategies can be added to the analyzerFamily array without touching index.js or the public API. bin/cli.js is a separate, thin wrapper around the same safeRegex call for batch JSON-file processing — it is not part of the core execution path.

Tech Stack Plain JavaScript with no runtime framework. The sole functional dependency is regexp-tree, used to parse a RegExp into an AST and traverse its Repetition nodes to compute nesting depth (star height) and total repetition count. The package is authored in src/ and built to dist/ (the published main entry) via Babel (@babel/cli, @babel/core, @babel/preset-env). Tests run under Jest. CI is configured through both a legacy .travis.yml and a GitHub Actions workflow (.github/workflows/npm-publish.yml) for publishing. There is no database, network I/O, or async code anywhere in the library — it is a pure, synchronous computation over a parsed AST.

Code Quality The Jest suite in src/test/regex.spec.js is thorough for the library’s scope: it exercises the full range of JS regex syntax (lookaround, named groups, backreferences), confirms linear- and polynomial-time patterns are accepted, confirms known exponential-time (nested-star) patterns are rejected, and explicitly documents — via inline TODO comments and dedicated test blocks — the analyzer’s known false positives and false negatives rather than hiding them. Coverage thresholds in package.json are set to 100% across statements, branches, functions, and lines. Error handling favors fail-safe defaults: invalid or unparseable regexes are caught and treated as unsafe rather than allowed to throw. There is no TypeScript and no linter configuration present in the repo, so type safety and style enforcement rely entirely on test coverage and code review.

API Design The public surface is deliberately minimal — one function, one options object, one boolean return value — which keeps integration nearly frictionless (if (!safeRegex(pattern)) reject()). The library’s specific technical choice is measuring structural “star height” from a parsed AST rather than matching against a list of known-dangerous regex shapes, a narrower but more principled heuristic than many naive ReDoS scanners use. It does not attempt full NFA state-space analysis (the author’s related vuln-regex-detector project targets that), and the README is explicit about the resulting blind spots, which is unusually honest developer-experience documentation for a security-adjacent utility.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search