TL;DR: A regular expression can pass code review, pass every test, and still take a production service to 100% CPU when someone sends it the right forty-character string. The class is well documented and the tooling is thin: linters flag a few known shapes, and proving a finding is real means running the pattern, which is the thing you were trying to avoid. PainHunt's security categories carry 6,870 high-scoring signals, and this cluster scores 12.9/15 on commercial potential.
The evidence
PainHunt's security, DevSecOps and AppSec categories hold 6,870 high-scoring signals (10+/15), average score 11.4, average pain intensity 8.0/10 across 31,543 extracted pain points. Sources are Mastodon (3,313), Medium (848), BlueSky (677), GitHub (535) and Dev.to (299).
Within the most recent extraction window, the DevTools/Security cluster scores 12.9 out of 15 on average — near the top of the candidates in that window — and describes the problem in unusually concrete terms:
- Vulnerable patterns pass review and tests, then cause outages. The failure is invisible under normal input and only appears under a crafted one.
- Detection tooling is thin. Practitioners describe existing static analysis as either absent or limited to string heuristics that miss real cases and flag safe ones.
- Testing safely is itself a problem. Verifying that a pattern is vulnerable means running it, which means a sandboxed process — otherwise the check is a self-inflicted denial of service.
- The bad patterns are inherited, not invented. They arrive by copy-paste from Stack Overflow answers and popular libraries, so "review your own regexes more carefully" does not reach them.
- The runtime offers no escape hatch. JavaScript has no regex timeout, no atomic groups and no possessive quantifiers, so the usual mitigations from other ecosystems are not available.
The personas are backend and platform engineers and DevSecOps teams — including, notably, teams at mid-size fintechs, where an unexplained CPU spike is an incident with a report attached.
Why now
Untrusted input reaches regular expressions more often. Every parsed webhook, uploaded file name, header and LLM-generated string is untrusted text, and validation is where regular expressions live. The attack surface grew without anyone deciding to grow it.
AI-assisted coding multiplied pattern volume. Generated code produces plausible regular expressions at a rate no reviewer inspects individually. Volume alone changes the odds, and the generated patterns inherit the same shapes from the same training material that the copy-paste path does.
Availability moved into scope. Once denial of service is a compliance and SLA concern rather than a theoretical one, "this pattern can hang a worker" stops being a code style comment and starts being a finding someone has to close.
The wedge
The narrow, buildable thing is turning a suspicion into a demonstration, safely.
- Parse, don't guess. Build the pattern into an abstract syntax tree and reason about which structures admit exponential paths. This is the difference between flagging every nested quantifier — most of which are fine — and flagging the ones that are reachable.
- Generate the attack string. A finding that ships with a concrete input reproducing the hang is a finding that gets fixed this sprint. A finding that says "this pattern may be vulnerable" gets a ticket and a year. This is the single highest-value output and the reason existing linters underperform.
- Run it in a sandbox with a hard budget. Verification executes the pattern against the generated input in a separate process with a strict time and CPU cap. Doing this correctly is the technically interesting part and the credible moat, because doing it incorrectly takes down the CI runner.
- Suggest the safe rewrite. Most vulnerable patterns have a mechanical fix — anchoring, bounded quantifiers, or a small parser instead of a regex. Shipping the rewrite alongside the finding closes the loop for the majority of cases.
- Gate at the pull request, not at the dashboard. The moment the pattern is introduced is the only cheap moment to fix it. A finding surfaced against a pattern that has been in production for two years is a negotiation; the same finding on a diff is a one-line change.
Risks and honest caveats
This is a feature-sized problem. It is a plausible module inside a SAST platform, not obviously a company. That cuts both ways: it is a realistic acquisition target and a realistic open-source-plus-hosted play, but it is a hard standalone enterprise sale.
The open-source baseline is decent and free. Several linters and analysers already cover part of this. Anything built here has to be materially better on the two axes buyers can verify in ten minutes — false positive rate, and whether the tool produces a working attack string — because those are the only claims a skeptical engineer will test.
False positives destroy adoption faster than missed findings. A security check that cries wolf gets muted, and a muted check is worse than none because it looks green. This argues for shipping high-confidence findings only and accepting real misses, which is an uncomfortable position for a security vendor to hold in a sales conversation.
Runtime scope narrows the market. The problem is sharpest in JavaScript and Node precisely because of the missing timeout. That focus is good product strategy and a real ceiling on total market size — worth naming out loud rather than discovering during fundraising.
Where this came from
This is one cluster inside PainHunt's security and DevSecOps categories. The Pain Point Browser shows the underlying signals with their intensity and commercial scoring, and the Idea Validator will score a specific version of this idea against the same dataset. Two adjacent clusters cover the same "the check exists but doesn't block" shape from other angles: enforcing commit rules that --no-verify can't bypass and quality gates for AI-generated code.