Mail-parser differentials and sandbox-option drop: Nodemailer addressparser divergences and resolveContent bypass¶
The September 17 GitHub wave ships a Nodemailer cluster that generalizes far beyond one npm package: two recipient-address parser differentials that defeat domain allow-lists by making the sender's parser disagree with the validator's parser, and a documented sandbox option silently dropped when content is resolved through the public plugin API.
| Advisory | Boundary | Operator value |
|---|---|---|
| GHSA-8pjj-q6q6-qm29 / CVE-2026-92597 | lib/addressparser mis-parses RFC 5322 comments: a comment closed immediately before a non-break character causes the atoms around the comment to concatenate — user@good-corp.com (x)evil.com reads as the single domain good-corp.comevil.com (attacker-registrable comevil.com) in both the SMTP envelope and the emitted headers, while a conformant parser terminates the domain at the comment (≥6.9.16, <9.1.0) | Any app that validates the recipient with a strict parser and then hands the raw string to the delivery library crosses a validator/sender differential |
| GHSA-r7q5-h7cx-p54x / CVE-2026-92598 | No UTS-46 normalization when encoding IDN domains: the resolver computes a different Punycode A-label than standards-compliant parsers, so invisible characters / compatibility mappings pass allow-list checks but deliver to attacker-controlled domains (<9.1.0) | IDN variant classes (confusables, ignorable code points, compatibility mappings) are allow-list bypass payloads whenever validator and sender normalize differently |
| GHSA-5635-p6jj-6g9p / CVE-2026-92595 | disableFileAccess/disableUrlAccess are not honored when message content is resolved via the legacy three-argument MailMessage.resolveContent(data, key, callback) signature: the missing options argument normalizes to {}, the message-level flags are discarded, and untrusted content reaches fs.createReadStream(path) or nmfetch(url) → arbitrary local file read / SSRF through plugin code (≤9.1.0, fixed 9.1.1) | Sandbox flags set at object construction can be dropped by an alternate public entry point — enumerate every API that reaches the same sink and check which ones thread the security options |
| GHSA-v554-hhrr-96v5 / CVE-2026-92596 | Quadratic-time addressparser input (tracked; DoS only) | — |
Lab-only validation
Prove differentials against your own mail lab (disposable SMTP sink you own, e.g. a local server that records the actual RCPT TO). Registering an attacker-domain lookalike is only acceptable for your own bug-bounty scope labs. Never inject test recipients into real user mailflows.
Why this is durable: the validator/sender differential pattern¶
The two addressparser bugs are one class: the application's allow-list parser and the mail-sending library's parser disagree on where the domain ends. The defensive assumption "we validated the domain, so delivery goes to the validated domain" fails whenever the sender re-parses the raw string with different grammar.
- Comment-atom concatenation. Test matrix around RFC 5322 comment placement:
(x)user@domain,user@(x)domain,user@dom(x)ain, and the shipped payloaduser@good-corp.com (x)evil.com. A conformant parser seesgood-corp.com; the vulnerable parser sees a single concatenated label. The observable is which domain the delivery layer connects to — captureRCPT TOand the resolved MX on your own sink, not just the app's validation verdict. - IDN normalization. Build a small corpus: zero-width joiners, U+00A8 vs U+0064 U+0069 diaeresis variants, full-width mappings, and a registered homograph lab domain. Submit through any address field feeding a mail or notification path. Evidence is a validation-accept/delivery-divergence decision table.
- Prefix/substring allow-lists first. The advisory notes naive
startsWith('good-corp.com')checks fail on the concatenated form even without parser differences. Test both layers separately: does the validator catch it, and does the sender deliver it? - This is the same family as the URL-parser differential findings on the Sept 15 Http4s/Traefik page and the Angular SSR trim-divergence page: two parsers, one string, security decision made by the wrong one. Generalize the audit to any validate-then-delegate pipeline (URL fetchers, git remotes, package specifiers, mail).
Sandbox-option drop via alternate entry point¶
The resolveContent bug is the reusable pattern for every library that advertises a sandbox:
- List every public function that reaches the guarded sink (file open, URL fetch, deserialization). Here
transporter.sendMail()internal paths honored the flags; the public plugin API legacy signature did not. - Read the option-threading code path: a missing argument normalized to an empty object is a silent security-option loss. Grep for
options || {}/ parameter-default collapse anywhere security flags travel. - In a plugin-based mail app, identify which code resolves message content — attachment paths,
hrefs,htmlfields from user input — and whether it goes through the affected signature. Proof is a synthetic path read of a lab marker file or an owned no-content callback hit, never a real secret file.
Reporting heuristics¶
- Lead with the exact string where the parsers diverge plus the parsed-domain output of both parsers side by side; the pair is the whole finding.
- Frame the impact honestly: delivery to an attacker-registrable domain requires the app's validation to gate a security decision (invite emails, verification links, invoice delivery). State which decision is bypassed; don't claim phishing success.
- For the sandbox drop, name the entry point that bypasses the control and show the internal path that honors it — the differential, not the file read itself, is the vulnerability.
Tracked without publication¶
- Quadratic-complexity
addressparserDoS (GHSA-v554-hhrr-96v5) and joiisoDate()unanchored-regex ReDoS (GHSA-mrx9-2rrp-rhpx / CVE-2026-92599) — availability-only, no reusable operator workflow beyond "cap input length," which the advisories already say. - TCH QRing BLE firmware item and quay-builder-qemu supply-chain note — hardware/scope-specific, tracked.
- HKUDS nanobot
< 0.3.0WebFetchTool SSRF (GHSA-mpqf-rmwr-h7wr / CVE-2026-92576,_validate_url()doesn't block RFC1918/localhost/metadata ranges) — tracked as another instance of the agent-fetch pattern already on the August 6 agent authority page; no new boundary beyond final-peer enforcement already documented there. - The n8n, Craft, and AVideo siblings of this wave live on their own pages (Craft wave, n8n page June-24 follow-up, AVideo page).
Source: hourly offensive-security scan, 2026-09-17 (00:31Z GitHub advisory wave). Tracked in the source index.