Patch Forecast
Yellow warning
Plan into this sprint.

GHSA-8vvx-rff5-p5rq

Nodemailer: Nested structured recipient arrays bypass the parser depth limit and cause stack exhaustion DoS

Risk score
45/100
CVSS
5.9 v3.1
Published
29 Sep 2026

Open in the live forecast Today's forecast

What to know

What it is
Nodemailer 10.0.1 does not safely process deeply nested arrays supplied through recipient fields such as to, cc, and bcc. The public MimeNodeAddressInput type recursively permits arrays, but MimeNode._parseAddresses() flattens only the outermost array. A remaining nested array is passed to addressparser(), whose Token…
Affected
nodemailer (npm) < 10.0.2
Fix
Upgrade nodemailer to 10.0.2 or later.
Exploitation
Public proof of concept

Story map

Story map: nodemailerTHE FLAWSTHE FIXGHSA-8vvx-rff5-p5rqNodemailer: Nested structuredrecipient arrays bypass theparser depth limit and cause…CVSS 5.9CVE-2026-90776Nodemailer addressparser:O(n^2) on comment-joinedaddresses enables a remote…CVSS 7.5 · EPSS 1%GHSA-v53p-9fqp-m79jNodemailer: Quadraticbacktracking in theaddressparser free-text…CVSS 7.5CVE-2026-110871Nodemailer: Quadratic (O(n^2))DKIM header unfolding lets alarge folded header cause…CVSS 6.5 · EPSS 0%Upgrade nodemailer10.0.10or later on your release lineWho is exposednodemailer (npm) >= 9.1.0, <=10.0.4AMBER · PATCH THIS WEEKnodemailernodemailer/lib/addressparserparses one shape of address inO(n^2) time. A single ~640 KBaddress value blocks the Node.jsevent loop for roughly 7 seconds.And it is reachable without auth:mailparser feeds inbound email…Where it standsPublic proof of conceptCONNECTS TOSame weaknessCWE-674 (CWE-674)56 other warnings in 30 days →
Story map: the flaws, the fix, how it unfolded and what it connects to. Boxes link to the record or article.

At a glance

nodemailer: Amber, patch this week. nodemailer/lib/addressparser parses one shape of address in O(n^2) time. A single ~640 KB address value blocks the Node.js event loop for roughly 7 seconds. And it is reachable without auth: mailparser feeds inbound email headers straight into this parser, so one crafted email is enough to stall a service that parses …

The flaws

  • GHSA-8vvx-rff5-p5rq: Nodemailer: Nested structured recipient arrays bypass the parser depth limit and cause stack exhaustion DoS (CVSS 5.9)
  • CVE-2026-90776: Nodemailer addressparser: O(n^2) on comment-joined addresses enables a remote DoS (reachable via mailparser) (CVSS 7.5 · EPSS 1%)
  • GHSA-v53p-9fqp-m79j: Nodemailer: Quadratic backtracking in the addressparser free-text fallback allows remote denial of service (CVSS 7.5)
  • CVE-2026-110871: Nodemailer: Quadratic (O(n^2)) DKIM header unfolding lets a large folded header cause remote denial of service during signing (CVSS 6.5 · EPSS 0%)

The fix

Upgrade nodemailer: 10.0.10 or later on your release line

Who is exposed: nodemailer (npm) >= 9.1.0, <= 10.0.4

Where it stands

  • Public proof of concept

Connects to

Why it is Yellow

  • CVSS 5.9 medium
  • Public exploit or proof of concept referenced
  • On your watchlist: npm

Affected packages

PackageEcosystemVulnerableFixed in
nodemailernpm< 10.0.210.0.2

References

Original description

## Submission metadata | Field | Value | |---|---| | Ecosystem | npm | | Package | `nodemailer` | | Repository | https://github.com/nodemailer/nodemailer | | Tested commit | `40d52215aac65b811d7e131bc916f68605efd9d2` | | Current tested version | `10.0.1` | | Confirmed vulnerable versions | `2.7.2`, `3.0.0`, `7.0.11`, `9.1.1`, `10.0.1` | | Proposed affected range | `>= 2.7.2, <= 10.0.1` | | Patched version | 10.0.2 | ## Summary Nodemailer 10.0.1 does not safely process deeply nested arrays supplied through recipient fields such as `to`, `cc`, and `bcc`. The public `MimeNodeAddressInput` type recursively permits arrays, but `MimeNode._parseAddresses()` flattens only the outermost array. A remaining nested array is passed to `addressparser()`, whose `Tokenizer` coerces the input with `.toString()`. Native `Array.prototype.toString()` recursively processes every nested array through `join()` and `toString()` until the V8 call stack is exhausted. A valid 10,021-byte JSON recipient value containing one address wrapped in 5,000 arrays causes: ```text RangeError: Maximum call stack size exceeded ``` The exception occurs through the normal `sendMail()` API before the `maxRecipients` limit is evaluated. If the integrating application does not catch the synchronous exception around the complete `sendMail()` invocation, the Node.js worker or server process terminates. No SMTP server, remote host, large attachment, or successful email delivery is required. This is distinct from GHSA-rcmh-qjqh-p98v / CVE-2025-14874. The previous vulnerability concerned recursive parsing of RFC 5322 group **strings**. This report uses Nodemailer's structured recipient-array input and never reaches the parser's `MAX_NESTED_GROUP_DEPTH` protection. ## Security impact An attacker who can control a recipient field passed to Nodemailer can trigger stack exhaustion using a roughly 10 KB JSON value. Potentially affected integrations include: - Email-sending HTTP APIs that accept structured recipient values. - Notification workers consuming JSON jobs from a queue. - Template or automation systems that forward parsed recipient data to `sendMail()`. - Multi-tenant applications that allow users to configure message recipients. When the exception is not caught, a single request or queue item can terminate the process handling mail. A process manager may restart the worker, but repeated malicious inputs can keep workers in a restart loop and make the service unavailable. Applications that explicitly validate recipient values as flat strings or flat arrays before calling Nodemailer are not exposed through this path. Applications that wrap the complete synchronous `sendMail()` invocation in exception handling can prevent process termination, although an attacker can still repeatedly force failed jobs. ## Attack prerequisites The vulnerability is reachable when: 1. An application accepts attacker-controlled or partially attacker-controlled recipient data. 2. The application preserves the array structure after parsing JSON. 3. The resulting value is passed to a Nodemailer recipient field such as `to`, `cc`, or `bcc`. 4. The application does not impose its own nesting-depth limit before calling Nodemailer. The proof of concept uses `jsonTransport` only to avoid requiring an SMTP server. The vulnerable address normalization and envelope construction occur before transport-specific delivery, so the root cause is not limited to `jsonTransport`. ## Technical details ### 1. The public input type accepts recursively nested arrays At `src/mime-node/index.ts:67`, recipient input is recursively defined: ```ts export type MimeNodeAddressInput = string | MimeNodeAddress | MimeNodeAddressInput[]; ``` Pinned source: https://github.com/nodemailer/nodemailer/blob/40d52215aac65b811d7e131bc916f68605efd9d2/src/mime-node/index.ts#L67 This permits values equivalent to: ```js [[[[['victim@example.test']]]]] ``` ### 2. `_parseAddresses()` removes only the outermost array At `src/mime-node/index.ts:1359-1385`, `_parseAddresses()` wraps the input with `[].concat(addresses)` and iterates the resulting outer array: ```ts _parseAddresses(addresses: MimeNodeAddressInput | undefined): MimeNodeAddress[] { const flattened: MimeNodeAddress[] = []; ([] as any[]).concat(addresses).forEach(address => { if (address && address.address) { const normalized = this._normalizeAddress(address.address); // ... return; } const parsed = this._normalizeParsedAddresses(addressparser(address)); for (let i = 0; i < parsed.length; i++) { flattened.push(parsed[i]); } }); return flattened; } ``` Pinned source: https://github.com/nodemailer/nodemailer/blob/40d52215aac65b811d7e131bc916f68605efd9d2/src/mime-node/index.ts#L1359-L1386 For an input nested 5,000 levels deep, the callback receives an array nested 4,999 levels deep. Because this value does not have a truthy `.address` property, it is passed directly to `addressparser()`. ### 3. `Tokenizer` invokes recursive native array conversion The `Tokenizer` constructor performs the following coercion at `src/addressparser/index.ts:393`: ```ts this.str = (str || '').toString(); ``` Pinned source: https://github.com/nodemailer/nodemailer/blob/40d52215aac65b811d7e131bc916f68605efd9d2/src/addressparser/index.ts#L393 When `str` is an array, this invokes `Array.prototype.toString()`. Array string conversion invokes `join()`, which converts every nested element to a string. Deeply nested arrays therefore produce native recursion resembling: ```text Array.toString -> Array.join -> childArray.toString -> Array.join -> childArray.toString -> ... ``` At sufficient depth, V8 raises `RangeError: Maximum call stack size exceeded`. ### 4. The recipient limit is applied too late Nodemailer's `maxRecipients` protection is evaluated only after the message envelope has been

Last activity 29 Sep 2026. Patch Forecast updates every hour.