Mar 28, 2026·6 min read·3 visits
A ReDoS vulnerability in path-to-regexp >= 8.0.0 and < 8.4.0 allows attackers to cause a Denial of Service by sending crafted paths to applications utilizing complex multi-wildcard routing patterns.
The path-to-regexp library, commonly utilized by Node.js frameworks like Express.js for routing, contains a Regular Expression Denial of Service (ReDoS) vulnerability in versions 8.0.0 through 8.3.0. The flaw is triggered when processing specific route patterns containing multiple wildcards, leading to CPU exhaustion and application downtime.
The path-to-regexp library serves as a foundational routing component in the Node.js ecosystem. It converts developer-defined path strings into regular expressions, which frameworks like Express.js use to map incoming HTTP requests to specific application logic. The library exposes a critical attack surface whenever it processes user-supplied URLs against complex route configurations.
CVE-2026-4923 represents a CWE-1333: Inefficient Regular Expression Complexity vulnerability. Versions 8.0.0 through 8.3.0 fail to safely compile routing patterns that contain multiple wildcards followed by a named parameter. When these specific patterns are used, the resulting regular expression is vulnerable to catastrophic backtracking.
Attackers submit specially crafted, artificially long URL paths to trigger this backtracking behavior in the V8 regex engine. The engine enters an exponential evaluation loop, resulting in complete CPU core exhaustion. Because Node.js relies on a single-threaded event loop architecture, this CPU exhaustion creates a severe Denial of Service (DoS) condition, halting all application processing.
The vulnerability originates in the regex generation logic for ambiguous capture groups. When the library parses routes containing sequences such as /*foo-*bar-:baz, it outputs regular expressions utilizing broad, greedy quantifiers (+) for the wildcard segments. Greedy quantifiers instruct the regex engine to consume as many characters as possible during the initial matching phase.
When multiple greedy wildcards are adjacent or overlapping, the engine loses deterministic boundaries between the segments. The regex engine must evaluate how to divide the input string among the available capture groups. If an input matches the initial wildcard segments but fails to satisfy the final parameter constraint (the :baz segment), the engine initiates a backtracking procedure.
During backtracking, the engine recursively attempts every possible distribution of the input string characters across the preceding wildcard groups. It trades characters one by one between the *foo and *bar segments, attempting to find a valid match path. This combinatorial explosion of state evaluations scales exponentially with the length of the input string, leading directly to the Denial of Service condition.
The remediation in version 8.4.0 introduces several structural changes to the regular expression compilation phase. The primary fix involves transitioning from greedy quantifiers to non-greedy or lazy quantifiers (+?) for wildcard and parameter capture groups. Commit 43669ac637fe70fad33693d145a74d98179152ce modifies the internal generation logic to use these lazy quantifiers.
// Vulnerable generation pattern (Conceptual)
const regex = /^(?:\/(.*))(?:\/(.*))(?:\/([^\/#\?]+?))[\/#\?]?$/i;
// Patched generation pattern (Conceptual)
const regex = /^(?:\/(.*?))(?:\/(.*?))(?:\/([^\/#\?]+?))[\/#\?]?$/i;The shift to lazy quantifiers prevents the engine from over-consuming characters initially. This drastically reduces the state space explored during a failure condition because the engine matches the minimum necessary characters for each segment before moving forward. Commit 4864654 also improved the negate function and added peekText and hasInSegment helpers to strictly delimit wildcard capture groups by their trailing literal characters.
Additionally, commit 22a967901afc8b2b42eefe456faa7b6773dcc415 implements a hard combinatorial limit. The library calculates the number of possible routing permutations during compilation. If a user-defined path involves so many optional groups or wildcards that it generates more than 256 internal permutations, the library throws a PathError. This preemptively blocks the compilation of inherently dangerous routing patterns.
Exploitation requires the target application to explicitly define a vulnerable routing pattern. The application must use path-to-regexp versions 8.0.0 through 8.3.0 and configure a route containing multiple wildcards where the final wildcard is not at the absolute end of the path string. Safe patterns include /*foo-:bar and /*foo-:bar-*baz.
An attacker crafts a malicious HTTP request targeting the vulnerable route. The request path consists of a repeating sequence of characters designed to match the wildcard segments, suffixed with a character that intentionally fails the final parameter match. The length of the repeating sequence dictates the severity and duration of the resulting CPU spike.
const { pathToRegexp } = require('path-to-regexp');
const { regexp } = pathToRegexp('/*foo-*bar-:baz');
// Input that causes backtracking:
const maliciousInput = "/-".repeat(50) + "!";
regexp.test(maliciousInput); // Node.js process hangsUpon receiving this request, the application attempts to match the path against the generated regular expression. The evaluation consumes the thread entirely. Multiple concurrent requests utilizing this payload will exhaust available worker threads or event loops across a clustered deployment, rendering the entire service unavailable.
The primary impact of CVE-2026-4923 is a severe Denial of Service condition affecting application availability. A blocking regular expression evaluation prevents the Node.js event loop from processing any subsequent HTTP requests, timers, or asynchronous callbacks. The application becomes completely unresponsive to legitimate user traffic.
The vulnerability carries a CVSS 3.1 base score of 5.9, reflecting the high impact on availability combined with a high attack complexity. The attack complexity is designated as high because exploitation is entirely dependent on the specific, developer-defined routing configuration. Applications using simple routing patterns are unaffected, regardless of the library version installed.
Confidentiality and integrity are not impacted by this vulnerability. The attacker cannot extract sensitive data, modify application state, bypass authentication, or execute arbitrary code. The impact is strictly isolated to computational resource exhaustion.
The definitive remediation for CVE-2026-4923 is upgrading the path-to-regexp dependency to version 8.4.0 or later. Organizations must utilize Software Composition Analysis (SCA) tools to identify all transitive and direct dependencies on the vulnerable versions, as path-to-regexp is frequently nested within framework dependency trees.
If an immediate dependency upgrade is impossible, developers must audit and refactor routing configurations. Routes must not contain multiple wildcards unless the final wildcard terminates the path string. Vulnerable patterns such as /*foo-*bar-:baz must be removed or rewritten to utilize explicit parameter definitions rather than catch-all wildcards.
Implementing strict input validation provides an effective defense-in-depth measure. Applications and Web Application Firewalls (WAFs) should enforce maximum length constraints on URL paths. Since ReDoS execution time scales exponentially with input length, truncating long paths prevents the regex engine from reaching catastrophic failure states.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
path-to-regexp pillarjs | >= 8.0.0, < 8.4.0 | 8.4.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1333 |
| Attack Vector | Network |
| CVSS Score | 5.9 (Medium) |
| EPSS Score | 0.0004 (0.04%) |
| Impact | High Availability (DoS) |
| Exploit Status | None (PoC available) |
| CISA KEV | Not Listed |
Inefficient Regular Expression Complexity