safe-regex2
Detects catastrophic, exponential-time regular expressions before they can freeze your app.
Repository Health
Technical Analysis
safe-regex2 is a small, focused npm library that checks whether a regular expression is safe to run against untrusted input. It parses the pattern into an abstract syntax tree using the ret library and walks that tree checking the nested “star height” of repetition constructs, rejecting anything with a star height greater than 1 or more repetitions than a configurable limit (25 by default) — the structural shape most associated with catastrophic, exponential-time backtracking.
It started as a fork of the original substack/safe-regex and is now maintained under the Fastify GitHub org, reflecting its main real-world use: guarding web frameworks, schema validators, and any code path that compiles a regex sourced from user or API input, so a single crafted pattern can’t hang the event loop in a ReDoS attack.
What You Get
- A single exported function,
safeRegex(re, opts), returning a plain boolean - A
safe-regex2CLI binary for checking a pattern from the terminal or a CI script (also runnable vianpx) - Bundled TypeScript type definitions with
tstychetype tests covering default and named imports - A configurable
opts.limitto tune how many repetition constructs are tolerated
Common Use Cases
- Validating user-supplied regex patterns before compiling them at runtime
- Guarding schema/validation libraries against regular-expression denial-of-service (ReDoS) input
- Linting regex literals in CI before they reach production
- Sanitizing regex patterns accepted through API request bodies or configuration files
Under The Hood
Architecture
The library is a single 77-line file with a purely functional design: safeRegex() normalizes its input (a RegExp object or string) via an isRegExp() check, then hands the pattern to ret’s parse() to build an AST, which a recursive walk() function traverses tracking starHeight and a cumulative repetition count against opts.limit, returning false the moment either threshold is exceeded. There is no internal state beyond the local opts object passed through the recursion, so the whole tree-walk short-circuits cleanly on the first unsafe node. The CLI (bin/safe-regex2.js) is a thin wrapper using Node’s built-in parseArgs that calls the same exported function, and types/index.d.ts mirrors the CommonJS export shape (module.exports plus .default/.safeRegex aliases) so the boolean contract holds identically whether a consumer imports it as CJS, ESM default, or a named export.
Tech Stack
It’s a pure CommonJS Node module with exactly one runtime dependency, ret (~0.5.0), the same regex-to-AST parser lineage the package’s fork history traces back through. Dev tooling is modern and minimal: c8 enforcing full test coverage, Node’s built-in node:test runner (no Jest or Mocha), neostandard plus ESLint 9’s flat config for linting, and tstyche for compile-time assertions against the bundled type declarations. There’s no build step — it ships raw JS and hand-written .d.ts files directly, and relies on Node’s native parseArgs/test APIs rather than external CLI or test frameworks.
Code Quality
The test suite exercises four explicit categories — safe patterns, unsafe/catastrophic patterns, the opts.limit override, and invalid/unparseable input — giving concrete regression coverage for the package’s entire security guarantee, with c8 --100 enforcing complete coverage on every run. Error handling is deliberately fail-safe: a try/catch around the parse step swallows any exception from ret and returns false rather than propagating, which is the correct behavior for a safety gate, though callers get no diagnostic detail on why a pattern was rejected. Naming stays minimal but clear, JSDoc annotates parameter shapes despite the code being plain JS, and GitHub Actions CI runs lint plus both unit and type tests on every change.
API Design
The public surface is one function with two aliases (.default, .safeRegex) so CommonJS default-import, named-import, and TypeScript default-import consumers all work without picking a specific convention. Getting started requires no configuration — safeRegex(re) works standalone — while opts.limit is the single well-documented escape hatch for teams whose legitimate patterns exceed the default repetition budget. The CLI mirrors that simplicity for ad-hoc terminal checks. Architecturally it isn’t attempting anything novel — it’s a well-scoped, actively maintained fork of the original substack/safe-regex, modernized with TypeScript types, dual-export ergonomics, a CLI, and Node’s native test runner rather than a new detection algorithm.
Used by 2 apps in this directory
Langfuse
AI Development · Monitoring
Open source AI engineering platform for LLM observability, prompt management, evaluation, and debugging — self-host in minutes or use Langfuse Cloud.
Tolaria
Note Taking
A free, open-source, local-first desktop app for managing markdown knowledge bases on macOS, Windows, and Linux — for second brains, company docs, or AI assistant memory and procedures.