Sep 8, 2026·6 min read·1 visit
Interpretation conflict in Nodemailer allows bypassing domain allow-lists to redirect sensitive emails to attacker-controlled domains.
Nodemailer (prior to version 9.1.0) is vulnerable to an IDN/Punycode domain allow-list bypass due to an interpretation conflict between legacy RFC-3492 codecs and modern UTS-46 Unicode parsers.
Nodemailer versions prior to 9.1.0 are vulnerable to an Internationalized Domain Name (IDN) and Punycode domain normalization bypass. This security flaw allows an attacker to bypass domain-based allow-lists or same-domain verification policies enforced by application logic. Consequently, emails containing sensitive information can be delivered to an unintended, attacker-controlled external domain.
The underlying security vulnerability arises from an interpretation conflict between standard URL parsers used for validation and Nodemailer's internal address normalization engine. Modern web frameworks, browsers, and backend validation packages process email domains using the UTS-46 Unicode standard. Conversely, older versions of Nodemailer processed domain components using a custom, legacy RFC-3492 Punycode codec with no Unicode normalization or compatibility mapping.
This architectural divergence creates a dangerous parsing asymmetry. An attacker can craft a recipient address containing invisible Unicode code points, full-width characters, or normalization discrepancies. The validation tier maps this address to a trusted domain, while Nodemailer resolves and routes it to an entirely separate, attacker-registered domain.
The root cause of GHSA-WMMP-3585-3RMP lies in the _normalizeAddress function within the lib/mime-node/index.js file. When compiling recipient addresses for the SMTP RCPT TO command, the library attempts to normalize the domain portion. Prior to version 9.1.0, Nodemailer passed the domain directly into a bundled, pure RFC-3492 Punycode library located at lib/punycode/ after only invoking a standard .toLowerCase() operation.
Standard RFC-3492 codecs perform basic encoding without any validation, character mapping, or normalization defined in the modern UTS-46 standard. UTS-46 defines rules for processing Unicode strings into domain labels. Under UTS-46, characters like the soft hyphen (U+00AD) are stripped, full-width characters are mapped to their half-width equivalents, and combined characters are normalized using Normalization Form C (NFC).
Because Nodemailer's legacy encoder bypassed these processing steps, it converted the input string literally. If an application validated an input email like user@compa\u00ADny.com using native APIs like Node's url.domainToASCII, the API stripped the soft hyphen and validated it as company.com. Nodemailer, however, processed the raw U+00AD character directly, yielding the Punycode domain xn--company-pka.com and misrouting the mail.
The following diagram illustrates the routing and normalization flow of an incoming email address through both the validation layer and the legacy Nodemailer library:
In the vulnerable implementation of lib/mime-node/index.js, the address normalization occurred inside the _normalizeAddress function. The code used a legacy, bundled punycode utility that did not align with WHATWG host requirements or UTS-46 standards. This is the vulnerable code segment:
// lib/mime-node/index.js (v9.0.6 - Vulnerable)
try {
if (/[\x80-]/.test(user)) {
// Uses legacy codec which encodes characters literally
encodedDomain = punycode.toUnicode(domain.toLowerCase());
} else {
// Bypasses UTS-46 normalization entirely
encodedDomain = punycode.toASCII(domain.toLowerCase());
}
} catch (_err) {
// Falls back to unnormalized input if encoding fails
}
return `${this._normalizeLocalPart(user)}@${encodedDomain}`;The security patch introduced a dedicated normalizeDomain helper that selectively utilizes the runtime environment's native urlModule.domainToASCII and urlModule.domainToUnicode utilities. To prevent delimiters from truncating input domains during WHATWG mapping, the maintainers defined a regular expression of unsafe URL characters, forcing the legacy codec fallback if delimiters are present:
// lib/mime-node/index.js (v9.1.0 - Patched)
// Prevent delimiters from truncating domains inside the WHATWG host parser
const URL_PARSER_UNSAFE = /[/\\?#%\x00-\x20\x7F]/;
function normalizeDomain(domain, toUnicode) {
// Select the native Node.js mapper if available (Node >= 7)
const mapper = toUnicode ? urlModule.domainToUnicode : urlModule.domainToASCII;
if (typeof mapper === 'function' && !URL_PARSER_UNSAFE.test(domain)) {
const mapped = mapper(domain);
if (mapped) {
return mapped;
}
}
// Fall back to legacy pure Punycode if unsafe characters or old Node version
return toUnicode ? punycode.toUnicode(domain) : punycode.toASCII(domain);
}Exploitation of this vulnerability requires that the target application enforces an email domain allow-list, same-domain restriction, or validation step that relies on standard UTS-46 parsers before delegating mail delivery to a vulnerable version of Nodemailer. The attacker must also register the corresponding divergent Punycode domain beforehand.
To conduct a typical attack, the adversary registers a lookalike domain, such as xn--company-pka.com. This domain represents compa\u00ADny.com containing the invisible soft hyphen code point (U+00AD). The attacker then registers or updates an account profile using the address attacker@compa\u00ADny.com containing the invisible character.
When the application processes this input, its native validator strips the soft hyphen and matches it against the approved allow-list for company.com. Once approved, the application calls Nodemailer to transmit sensitive data, such as a password reset token, to the validated email address. Nodemailer processes the raw soft hyphen literal and translates the destination to the attacker's registered domain xn--company-pka.com, routing the email to the attacker's SMTP mail exchanger.
The security impact of this vulnerability is classified as Medium, with a CVSS v3.1 base score of 5.9. The primary compromise is the loss of confidentiality. Because sensitive transactional emails, such as password reset tokens, security notifications, multi-factor authentication codes, or tenant-specific alerts, can be silently redirected to an attacker-controlled mailbox, this flaw represents a severe data exposure vector.
The integrity impact is evaluated as Low. Although the application is unaware that the email was misrouted and may register a successful transaction state, the mail payload itself is not altered in transit. The availability impact is rated as None, as exploitation does not degrade the operational availability of the mail-sending system or the SMTP server.
Because this vulnerability does not possess a mapped CVE ID and is a GHSA-only advisory, it is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. No widespread automated in-the-wild exploitation has been documented, but proof-of-concept scripts have demonstrated successful local exploitation against vulnerable test environments.
The primary remediation strategy is upgrading the nodemailer dependency to version 9.1.0 or higher. This version natively integrates standard UTS-46 normalization with WHATWG host delimiter hardening, aligning Nodemailer's domain processing with standard application-tier validators.
If upgrading the library is not immediately feasible, developers must implement strict input normalization on the application side. Any email input should be parsed and processed using Node's native url.domainToASCII before performing validation checks or passing the address to Nodemailer. This ensures that both the application validation and the mail-routing components evaluate the exact same domain string.
Furthermore, security teams should implement defensive filters at the application entry points. Reject any email addresses containing unexpected Unicode control characters, soft hyphens, or path delimiters within the domain part. Regular monitoring of outgoing SMTP logs for unusual Punycode domains (identifiable by the xn-- prefix) can also serve as an effective detection mechanism.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
nodemailer Nodemailer | < 9.1.0 | 9.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-436 / CWE-20 |
| Attack Vector | Network |
| CVSS Score | 5.9 (Medium) |
| Exploit Status | PoC available |
| KEV Status | Not listed |
| Mitigation | Upgrade to Nodemailer 9.1.0+ |
An algorithmic complexity vulnerability in Nodemailer before version 9.1.0 allows remote attackers to block the Node.js event loop. This denial of service is triggered by processing large or complex lists of email addresses, leading to quadratic resource consumption.
A missing authorization vulnerability (CWE-862) exists in n8n where AI Agent workflows executing as tools bypass the Sub-Workflow Caller Policy settings, allowing authenticated users with agent creation privileges to invoke unauthorized sub-workflows across project boundaries.
A Denial of Service (DoS) vulnerability exists in the xmldom library when parsing HTML-mode documents with mixed-case closing tags for raw-text or escapable raw-text elements like script, style, textarea, or title. This leads to algorithmic complexity issues and quadratic output amplification during DOM serialization.
A command-line option injection vulnerability in GitPython allows low-privilege or unauthenticated actors to read arbitrary local files. The flaw resides in the TagReference.create() function, which fails to evaluate positional arguments against the library's unsafe-option denylist, enabling the execution of native git commands with injected option flags.
GitPython prior to version 3.1.59 contains a path traversal vulnerability via parameter injection. The clone denylist did not restrict the `--separate-git-dir` option, allowing attackers to write repository metadata to arbitrary system paths.
CVE-2026-72925 is a critical vulnerability in the SWC HTML minifier (@swc/html and swc_html_minifier) where safe Unicode-escaped characters in embedded JSON script tags are normalized into raw, unescaped characters during optimization, causing browser-side HTML injection and Cross-Site Scripting.