Sep 30, 2026·6 min read·3 visits
A ReDoS vulnerability in Nodemailer before 10.0.6 allows unauthenticated attackers to cause a remote denial of service by sending crafted email headers that block the single-threaded Node.js event loop.
A Regular Expression Denial of Service (ReDoS) vulnerability exists in Nodemailer's addressparser fallback engine before version 10.0.6. Under specific malformed inputs with excessive word boundaries, the parser exhibits quadratic backtracking, leading to high CPU utilization and event loop blockage.
The vulnerability tracked under GHSA-V53P-9FQP-M79J resides in the fallback address parsing component of the popular Node.js email delivery library, Nodemailer. When strict parsing of email headers fails, the application switches to a fallback engine designed to scan unstructured text and recover potential email strings. This behavior exposes a significant attack surface because email headers often contain untrusted input supplied directly by external sources.
The vulnerable component, addressparser, uses an inefficient fallback regular expression to locate potential email formats. When processing specific malicious strings, the engine's backtracking limits are exceeded, triggering catastrophic backtracking. This causes a Regular Expression Denial of Service (ReDoS) that completely blocks the execution flow.
Because Node.js operates on a single-threaded event loop, blocking CPU execution for several seconds directly halts all concurrent processing. An unauthenticated attacker can exploit this behavior remotely to deny service to the entire application. The underlying weakness is classified under CWE-1333 (Inefficient Algorithmic Complexity) and CWE-400 (Uncontrolled Resource Consumption).
The root cause of the vulnerability lies in the implementation of the loose fallback search algorithm within src/addressparser/index.ts. When evaluating input, the parser executes the regular expression /\s*\b[^@\s]+@[^\s]+\b\s*/ globally across unstructured sections of email headers. The lack of an anchor (such as ^ or $) or a sticky flag (/y) forces the engine to evaluate possible matches from multiple starting positions within the string.
When the input contains sequences of non-whitespace characters separated by word boundaries but missing the @ symbol, the engine is forced into a quadratic execution path. Consider an input containing repeating characters with word boundaries, such as [x][x][x]...[x]. The regular expression engine matches the word boundary \b, greedily consumes the string using [^@\s]+, and scans to the very end of the line.
Upon failing to locate the literal @ character at the end of the line, the engine must backtrack. It drops one character at a time and attempts to match the remaining terms, failing repeatedly. Once the engine exhausts all backtracking permutations for the first starting index, it increments the index to the next word boundary and repeats the entire greedy scan and backtracking cycle. This sequence creates an $O(N^2)$ time complexity, transforming an input of only 273 kilobytes into a CPU loop that blocks execution for up to 43 seconds.
A comparison of the codebase before and after the patch illustrates the transition from an unbounded regular expression search to a deterministic linear-time pre-scanner. In the vulnerable version, the library relied on a simple string replacement pattern with an unconstrained regular expression:
// Vulnerable implementation in src/addressparser/index.ts
data.text[i] = data.text[i]
.replace(/\s*\b[^@\s]+@[^\s]+\b\s*/, (match: string) => {
// Extracts and processes matching address strings
});The patch, committed under SHA 437d7fc47403df176bc39271641541b7a9bce102, replaces this pattern entirely. The developer introduced a manual index searcher, _looseAddressStart, which scans the string character-by-character to locate a candidate offset in strictly $O(N)$ linear time. The regular expression itself is modified to use the sticky flag (/y), preventing arbitrary forward scanning.
// Patched implementation in src/addressparser/index.ts
const LOOSE_TEXT_ADDR = /\s*\b[^@\s]+@[^\s]+\b\s*/y; // Note the sticky flag
const part: string = data.text[i];
let remainder = part;
const at = _looseAddressStart(part); // O(N) pre-scanner determines candidate start
if (at >= 0) {
LOOSE_TEXT_ADDR.lastIndex = at; // Restrict search to exact offset
const match = LOOSE_TEXT_ADDR.exec(part);
if (match) {
data.address = [match[0].trim()];
extracted = true;
remainder = part.slice(0, at) + ' ' + part.slice(at + match[0].length);
}
}
data.text[i] = remainder.trim();By implementing _looseAddressStart, the parser avoids activating the regular expression engine unless a valid candidate offset is verified. If the pre-scanner fails to find a valid @ candidate bounded by appropriate characters, the search aborts early without triggering the expensive backtracking engine. This completely mitigates the quadratic vulnerability.
To trigger the vulnerability, an attacker must submit a specifically formatted payload to an application endpoint that processes email headers through the addressparser module. The exploit payload relies on generating a large quantity of word boundaries without containing a valid email delimiter @. This forces the regex parser to exhaustively evaluate backtracking configurations at each boundary location.
The most reliable payload configuration involves repeating the sequence [x] multiple times to construct an extremely dense array of word boundaries. For example, generating a string containing 40,000 instances of [x] creates a payload of approximately 120 kilobytes. When this payload is sent through an unstructured email header field, it triggers immediate CPU saturation.
The exploitation does not require authentication and can be delivered via any input vectors that map directly to mail components such as To, From, or Cc. In typical production systems, receiving an inbound email message with these malformed headers causes the mail processor thread to hang indefinitely. This blocks any subsequent network requests and degrades the overall application availability.
The security impact of GHSA-V53P-9FQP-M79J is significant due to the single-threaded nature of the Node.js runtime environment. When a CPU-bound operation like quadratic backtracking occurs, the event loop is entirely blocked, and the application cannot process incoming HTTP requests, database updates, or basic system events. This creates a highly effective denial-of-service condition with minimal resource expenditure by the attacker.
We assign this vulnerability a CVSS v3.1 base score of 7.5 (High), reflecting the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H. The attack vector is network-based, the complexity is low, and no specialized privileges or user interactions are required to trigger the condition. The overall integrity and confidentiality of the host environment remain intact, as the exploit does not permit unauthorized read or write access.
Because Nodemailer is a fundamental dependency utilized across thousands of production Node.js applications, the downstream exposure is substantial. While no active exploitation has been documented in wild campaigns, the availability of stable proof-of-concept scripts increases the probability of opportunistic exploitation against exposed email ingestion gateways.
Remediating this vulnerability requires upgrading the nodemailer package to version 10.0.6 or later. The update completely replaces the vulnerable regex backtracking pattern with the deterministic linear pre-scanner. Development teams should audit their project lockfiles to verify that transitive dependencies do not pull in vulnerable legacy versions of the package.
If immediate patching is not feasible due to deployment freezes, security teams should implement input validation controls at the network perimeter. Configuring a Web Application Firewall (WAF) or API gateway to enforce length restrictions on incoming email header fields provides effective temporary mitigation. A strict limit of 4096 bytes on structured headers will disrupt the execution of the quadratic exploit payload.
Additionally, developers can implement a runtime input pre-filtering mechanism to intercept large unstructured blocks before they are evaluated by the parser. Stripping out excessive special character patterns or rejecting inputs with high frequencies of non-alphanumeric transitions can reduce the risk of denial of service. However, these temporary workarounds should not replace the official package upgrade.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
nodemailer nodemailer | < 10.0.6 | 10.0.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1333 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 7.5 (High) |
| Impact | Remote Denial of Service (DoS) |
| Exploit Status | Proof-of-Concept (PoC) |
| KEV Status | Not Listed |
The product uses a regular expression that can be made to perform extremely inefficient backtracking when processing certain inputs.
A signature verification bypass vulnerability in PyJWT allows unauthenticated remote attackers to forge JSON Web Tokens when processing JSON Web Key Sets containing an empty symmetric key.
Nodemailer versions prior to 10.0.9 are vulnerable to a parser differential bug. When processing a quoted local-part followed by an RFC 5322 comment and trailing characters, the internal addressparser module fails to order its normalization routine correctly. This error results in the generation of malformed envelope recipient addresses containing injected whitespace and secondary domains, allowing attackers to bypass routing restrictions and exfiltrate sensitive emails.
CVE-2026-102276 is a high-severity Denial of Service (DoS) vulnerability impacting the 'brace-expansion' library, a popular Node.js utility designed to expand brace patterns into combinatorial lists. Due to uncontrolled recursion and argument-list stack exhaustion within the internal parseCommaParts function, remote attackers can trigger an unhandled RangeError that abruptly terminates the Node.js process.
A stack-based Denial of Service (DoS) vulnerability via uncontrolled recursion in the brace-expansion library prior to versions 1.1.20, 2.1.6, 3.0.8, and 5.0.11 allows unauthenticated remote attackers to trigger native stack exhaustion, terminating the Node.js process via a crafted payload containing deeply nested brace groups.
An uncontrolled resource consumption vulnerability exists in the brace-expansion JavaScript library. Due to an algorithmic flaw in parsing a legacy Bash-compatibility quirk involving {a},b}-shaped expansion structures, untrusted inputs containing many trailing closing braces trigger successive full-input rescans. This behavior yields quadratic CPU time complexity and high memory overhead, allowing remote, unauthenticated attackers to cause a Denial of Service (DoS) by blocking the single-threaded Node.js event loop.
Moment.js versions 2.29.2 through 2.30.1 are vulnerable to a Path Traversal flaw (CWE-27) on server-side Node.js environments when dynamic locales are configured. The vulnerability stems from an object-coercion bypass in the locale-name sanitization routine, which assumes incoming variables are string primitives. An attacker can pass a structured object with custom 'match' and 'toString' properties to bypass regex-based directory checks, leading to arbitrary file loading via Node's internal 'require()' call.