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
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
- Same weakness: CWE-674 (CWE-674). 56 other warnings in 30 days
Why it is Yellow
- CVSS 5.9 medium
- Public exploit or proof of concept referenced
- On your watchlist: npm
Affected packages
| Package | Ecosystem | Vulnerable | Fixed in |
|---|---|---|---|
| nodemailer | npm | < 10.0.2 | 10.0.2 |
References
- https://github.com/advisories/GHSA-8vvx-rff5-p5rq
- https://github.com/nodemailer/nodemailer/security/advisories/GHSA-8vvx-rff5-p5rq
- https://github.com/nodemailer/nodemailer/commit/ebe084940aef88278afc6016b78c6d1c3821bb66
- https://github.com/nodemailer/nodemailer/releases/tag/v10.0.2
- https://github.com/advisories/GHSA-8vvx-rff5-p5rq
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.