Skip to content
Security & Trust

One Regex Pattern Freezes the Entire Server: ReDoS in DOM Libraries

A ReDoS vulnerability in @asymmetric-effort/nogginlessdom exposes a systemic risk in server-side DOM implementations. HTMLInputElement.checkValidity() passes user-controlled patterns directly to RegExp with no sanitization or timeout. In SSR environments, one malicious form input freezes the Node.js event loop for every user.

· 4 min read
Share on X LinkedIn
One Regex Pattern Freezes the Entire Server: ReDoS in DOM Libraries

Browser APIs Were Never Meant to Run on Servers

A GitHub advisory disclosed a ReDoS (Regular Expression Denial of Service) vulnerability in @asymmetric-effort/nogginlessdom, a DOM implementation used in server-side rendering and testing environments. The vulnerability is in HTMLInputElement.checkValidity(), which constructs a RegExp object directly from the element's pattern attribute — a value controlled entirely by user input. No sanitization. No complexity limits. No timeout protection. A crafted pattern triggers catastrophic backtracking, and the JavaScript engine will spend minutes or hours evaluating a single regex match.

In a browser, this is a nuisance. The browser's regex engine runs in a sandboxed thread, and the worst outcome is a frozen tab that the user can close. On a server, this is a denial of service. Node.js runs JavaScript on a single event loop. One request's catastrophic regex evaluation blocks every other request from being processed. The server does not slow down — it stops.

1
Event loop threads in Node.js
Node.js processes all JavaScript on a single thread. One blocked operation halts all request handling. Source: Node.js documentation.

The Pattern That Breaks Everything

HTML5 form validation allows developers to set a pattern attribute on input elements — a regex that the browser evaluates when the form is submitted. The spec delegates regex evaluation to the browser engine, which implements internal safeguards: execution timeouts, backtracking limits, and thread isolation. When a library like nogginlessdom reimplements checkValidity() in pure JavaScript, none of those safeguards exist. The library calls new RegExp(element.pattern) and executes it with no protection.

Catastrophic backtracking is a well-understood class of regex vulnerability. Patterns with nested quantifiers — such as (a+)+ or (a|a)* — cause the regex engine to explore an exponential number of possible matches. A 30-character input string against a malicious pattern can require over one billion backtracking steps. In server-side JavaScript, that translates directly to a frozen event loop.

~34%
ReDoS share of Node.js DoS vulnerabilities
ReDoS accounts for roughly one-third of all denial-of-service vulnerabilities reported in the Node.js ecosystem. Source: Davis et al., 'The Impact of Regular Expression Denial of Service in Practice,' FSE 2018 / Snyk vulnerability database.

SSR Environments Are Single-Threaded Targets

Server-side rendering frameworks process HTML on the server before sending it to the client. If that processing pipeline includes DOM libraries that evaluate form validation — parsing user-submitted HTML, running test suites against form components, or pre-rendering interactive elements — the regex execution happens in the server's main thread. One request carrying a malicious pattern attribute blocks the entire SSR pipeline.

This is not a theoretical risk. The npm registry contains dozens of DOM implementations designed for server-side use: jsdom, happy-dom, linkedom, and nogginlessdom among them. Each one must decide how to handle browser APIs that assume sandboxed execution. The HTML specification defines checkValidity() behavior but does not specify timeout or complexity protections — those are implementation details left to browser vendors. Server-side implementations that follow the spec without adding equivalent protections inherit the vulnerability.

27M+
jsdom weekly npm downloads
jsdom alone averages over 27 million weekly downloads, indicating massive server-side DOM usage across testing and SSR. Source: npm registry (July 2026).

The Broader Pattern: Browser Safety Assumptions in Server Code

The nogginlessdom vulnerability is one instance of a structural problem: DOM APIs that were designed with browser-level protections are being reimplemented in environments that lack those protections. Browsers enforce execution budgets, thread isolation, and resource limits that are invisible in the specification. When server-side libraries implement the same API surface without the same guardrails, they create denial-of-service vectors that the original API designers never anticipated.

This extends beyond regex. Any DOM API that processes unbounded user input — innerHTML parsing, CSS selector matching, custom element lifecycle callbacks — carries risk when moved from a sandboxed browser tab to a shared server process. The web platform's security model assumes that each user operates in an isolated context. Server-side DOM breaks that assumption by running every user's input in the same process, on the same thread, with the same event loop.

Mitigation: What Server-Side DOM Libraries Must Do

Server-side DOM implementations processing user-controlled input need three protections that browsers provide implicitly: regex complexity analysis before execution, hard timeouts on pattern evaluation, and isolation of untrusted input processing from the main event loop. Libraries can use packages like safe-regex or re2 (Google's linear-time regex engine) to reject or sandbox dangerous patterns before they reach the JavaScript regex engine. Without these protections, every checkValidity() call on user-controlled HTML is a potential denial-of-service trigger.

For organizations running SSR pipelines that process untrusted HTML: audit your DOM library's handling of the pattern attribute, innerHTML, and any API that evaluates user-controlled strings as code or patterns. The browser was never just rendering your page — it was also protecting your server from inputs it never had to process. That protection does not transfer when you move the DOM to Node.js.

Zero
Google RE2 backtracking
RE2 guarantees linear-time matching by design, eliminating catastrophic backtracking entirely. Source: Google RE2 documentation.
Share this insight