Jun 15, 2026·8 min read·9 visits
A CRLF injection vulnerability in Nodemailer <= 8.0.8 allows remote attackers to inject arbitrary email headers by placing newline characters inside dynamic List-* header comments. This occurs because 'prepared' headers bypass Nodemailer's standard sanitization pipeline.
GHSA-268h-hp4c-crq3 is a Carriage Return Line Feed (CRLF) injection vulnerability in the Nodemailer npm package affecting versions up to and including 8.0.8. The library allows arbitrary email header injection when parsing user-controlled comments within list headers (such as List-Unsubscribe or List-ID). This occurs because list headers bypass standard validation by utilizing an internal 'prepared' flag, causing unsanitized newlines to be emitted directly into the outgoing RFC822 mail stream. This exploit allows remote attackers to inject custom, unauthorized mail headers, disrupting signature checks, bypassing filters, or spoofing parameters.
Nodemailer is an open-source library for Node.js applications that facilitates outbound email transmission via SMTP or transport streams. To support standard newsletter and list features, Nodemailer includes native parsing for List-* headers as defined in RFC 2369 and RFC 2919. These headers, such as List-Unsubscribe, List-Help, and List-ID, allow modern mail clients to display standardized administrative buttons (e.g., Unsubscribe) above the main message body.\n\nThe attack surface is exposed when applications dynamically populate list parameters with user-provided metadata, such as comment descriptors or user-specific unsubscribe configurations. While standard mail headers in Nodemailer undergo rigorous input sanitation to strip or normalize control sequences, list headers are handled by a specialized compilation pipeline. This pipeline flags the resulting values as trusted, pre-compiled payloads, effectively preventing downstream sanitation filters from executing validation routines on these parameters.\n\nIf an attacker can control the comment portion of a list header configuration (e.g., list.unsubscribe.comment or list.id.comment), they can inject Carriage Return (\r) and Line Feed (\n) sequences. These control sequences act as raw layout boundaries in the final RFC822 output stream. Because the message structure splits fields strictly based on CRLF boundaries, the parser treats the trailing portion of the comment as a standalone, root-level message header. This security flaw is classified as CWE-93 (Improper Neutralization of CRLF Sequences).
The root cause resides in the differential handling of headers inside the Nodemailer compiler core. Specifically, the vulnerability manifests when constructing list headers in lib/mailer/mail-message.js and subsequently generating the stream layout in lib/mime-node/index.js. Standard header fields undergo an escaping pipeline where literal raw control characters are converted into spaces or safely wrapped using RFC 2047 MIME encoding. In contrast, list headers are compiled via the internal helper _getListHeaders(this.data.list).\n\nDuring compilation in lib/mailer/mail-message.js (lines 241-296), each configured list entry is parsed into a structured header object. For instance, the compilation of the List-ID comment field checks if the parameter is plain text using mimeFuncs.isPlainText(comment). If this is evaluated as true, the parser wraps the comment in parentheses and embeds it into the header value directly. However, the evaluation relies solely on the characters falling within printable ASCII ranges and completely fails to neutralize or reject raw CRLF (\\r\\n) sequences.\n\nCrucially, when these list header structures are finalized, they are returned with a specifier configuration of { prepared: true, foldLines: true, value: ... }. The prepared attribute is an internal flag instructing Nodemailer's MIME layout generator to skip regular sanitization, parsing, and escaping processes under the assumption that the value was already normalized. In lib/mime-node/index.js (lines 323-351), the layout engine detects this flag and calls mimeFuncs.foldLines(key + ': ' + value) directly. The unsanitized payload, containing the raw CRLF sequences, is outputted into the outgoing RFC822 transport stream, executing the injection.
To understand the vulnerable code path, we examine how the list headers are constructed in lib/mailer/mail-message.js before being passed to lib/mime-node/index.js. The vulnerable compilation logic for list headers is as follows:\n\njavascript\n// Vulnerable snippet in lib/mailer/mail-message.js\n// For list properties, headers are dynamically generated and marked as 'prepared'\nlet value = this._getListHeaders(this.data.list);\n\n// Inside _getListHeaders implementation:\nif (item.comment) {\n // The library only checks if the comment is plain text\n // but does not sanitize or strip actual CRLF characters\n if (mimeFuncs.isPlainText(item.comment)) {\n commentStr = '(' + item.comment + ')';\n } else {\n commentStr = mimeFuncs.encodeWord(item.comment);\n }\n}\n\n// The resulting compiled list headers are added with the prepared flag:\nthis.message.addHeader(listHeader.key, {\n prepared: true,\n foldLines: true,\n value: formattedValue + (commentStr ? ' ' + commentStr : '')\n});\n\n\nWhen the MIME generator in lib/mime-node/index.js processes headers, it checks the configuration of the incoming header object. Regular headers undergo strict sanitization, but prepared headers bypass validation completely, as illustrated below:\n\njavascript\n// Inside lib/mime-node/index.js\n_postProcessHeaders(headers) {\n // ...\n if (header.prepared) {\n // Security Bypass: No CRLF validation or sanitization is conducted\n // The raw string is folded and pushed directly to the header output block\n this._headers.push(mimeFuncs.foldLines(header.key + ': ' + header.value));\n } else {\n // Safe path: Sanitizes raw header strings to prevent boundary injection\n let sanitizedValue = this._sanitizeHeaderValue(header.value);\n this._headers.push(mimeFuncs.foldLines(header.key + ': ' + sanitizedValue));\n }\n // ...\n}\n\n\nThis implementation path demonstrates that the prepared attribute establishes an implicit trust boundary. Because Nodemailer treats internal helpers as secure components, any omission of validation in the upstream _getListHeaders function leads to an unmitigated injection path. The patch in version 8.0.9 addresses this by sanitizing CRLF sequences in _getListHeaders before compiling the comment into the final output value.
Exploiting GHSA-268h-hp4c-crq3 requires an application flow that passes dynamic user input into the comment fields of a list header configuration. The attacker inserts a Carriage Return (\r) and Line Feed (\n) sequence followed by the target header field they wish to inject. Since MIME messages rely on CRLF as structural delimiters between discrete headers, the injected CRLF sequences terminate the List-* header early and initiate a new header context.\n\nConsider an application that allows users to define custom list titles or unsubscribe notes, which are then passed to Nodemailer's sendMail parameters. An attacker can set the comment parameter to the following payload:\n\nmy-comment\\r\\nX-Injected-Header: InjectedValue\n\nWhen Nodemailer compiles the list header, it builds the string representation inside parentheses: (my-comment\\r\\nX-Injected-Header: InjectedValue). Because this is marked as prepared: true, the literal value is written directly to the output stream. The physical output sequence appears as:\n\nhttp\nList-Unsubscribe: <https://example.com/unsubscribe> (my-comment\r\nX-Injected-Header: InjectedValue)\r\n\n\nTo downstream SMTP servers and email clients, this payload is parsed as two distinct headers: a truncated List-Unsubscribe header and a standalone X-Injected-Header. The payload does not corrupt the remaining structure of the mail envelope, making the injection clean and difficult to detect without inspecting raw message sources. This bypass is highly reliable as it relies strictly on RFC822 layout parsers that are structurally bound to split headers on CRLF boundaries.
The impact of CRLF injection within an email rendering and delivery library is significant. First, an attacker can exploit this vulnerability to bypass spam and email security filter mechanisms. Many security appliances assess outbound or inbound email posture by evaluating structural headers. By injecting headers like X-Spam-Threshold, Precedence: bulk, or custom trust headers, attackers can systematically manipulate the spam classification scoring of their payloads, allowing phishing emails to reach the victim's inbox.\n\nSecond, the flaw can be leveraged for advanced social engineering and phishing attacks. Attackers can inject custom header fields such as Reply-To, Sender, or mail-client-specific priority configurations. This allows the attacker to alter the visually represented sender or reply destination in common mail applications, tricking recipients into sending sensitive information to unauthorized endpoints.\n\nThird, this injection can compromise cryptographic message integrity. Standard email signatures like DKIM (DomainKeys Identified Mail) sign specific headers or header structures to prove origin integrity. By injecting additional headers or altering existing ones, attackers can break DKIM signatures or cause downstream Mail Transfer Agents (MTAs) to discard or flag authentic mail as forged. If the injection contains multiple CRLF sequences, it can even prematurely terminate the header block, injecting arbitrary text or HTML into the message body itself.
To remediate this vulnerability, software developers must upgrade nodemailer to version 8.0.9 or higher. This release corrects the flaw by integrating sanitization steps within the list compiler, ensuring any list.*.comment option has carriage return and line feed characters neutralized or rejected prior to building the prepared header payload.\n\nIf an immediate upgrade of the package is not feasible due to regression risks or environment constraints, developers must implement input-validation wrappers to cleanse inputs before passing them to the Nodemailer parameters. A strict sanitization regex should be applied to any user-controlled comment inputs to strip out Carriage Return and Line Feed control characters. The following sanitization implementation is recommended for legacy deployments:\n\njavascript\nfunction sanitizeListComment(comment) {\n if (typeof comment !== 'string') {\n return comment;\n }\n // Strip carriage returns and line feeds to neutralize injection vector\n return comment.replace(/[\\r\\n]+/g, '');\n}\n\n// Implement within mail configuration flow\nconst mailOptions = {\n from: 'no-reply@example.com',\n to: 'user@example.com',\n subject: 'Unsubscribe Confirmation',\n list: {\n unsubscribe: {\n url: 'https://example.com/unsubscribe',\n comment: sanitizeListComment(req.body.userComment)\n }\n }\n};\n\n\nIn addition to local sanitization, security teams should configure Web Application Firewalls (WAFs) and application runtimes to inspect incoming request parameters for raw or URL-encoded carriage returns (%0D, %0A, \\r, \\n) targeting parameters destined for email construction modules. This multi-layered defense minimizes the likelihood of exploitation.
| Product | Affected Versions | Fixed Version |
|---|---|---|
nodemailer nodemailer | <= 8.0.8 | 8.0.9 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-93 |
| Attack Vector | Network (Remote) |
| CVSS Score | 5.4 |
| Exploit Status | poc |
| Impact | Arbitrary Email Header Injection |
| Fixed Version | 8.0.9 |
An LDAP injection vulnerability exists in the centraldogma-server-auth-shiro module of LY Corporation Central Dogma before version 0.84.0. The search logic dynamically constructs LDAP search filters by interpolating user-provided usernames without escaping RFC 4515 metacharacters. Unauthenticated remote attackers can leverage this flaw to bypass authentication, enumerate directory hierarchies, and access unauthorized resources.
CVE-2026-11746 is a critical vulnerability in Central Dogma Server prior to version 0.84.0, where an embedded ZooKeeper replication secret silently falls back to a publicly known, hard-coded default string ('ch4n63m3'). Remote attackers with access to the replication network can authenticate as legitimate cluster peers, potentially leading to unauthorized data exposure, state manipulation, or complete cluster takeover.
A logical verification flaw in ZITADEL's external JWT Identity Provider validation allows attackers to bypass session expiration checks. If an incoming JWT lacks the 'exp' claim, the system skips validation entirely, creating an indefinitely valid session. This issue has been addressed in versions 3.4.12 and 4.15.2.
CVE-2026-59149 identifies a directory traversal vulnerability in `@mockoon/commons-server`, the backend mock-server library powering the Mockoon application. The flaw occurs in the path containment validation logic used during raw file response generation. An unauthenticated attacker can exploit this weakness to retrieve arbitrary files from sibling directories sharing a common prefix with the designated static base directory.
An in-depth analysis of CVE-2026-59148, a high-severity flaw in Mockoon where unauthenticated administrative endpoints and a wildcard Cross-Origin Resource Sharing (CORS) policy allow remote execution, state poisoning, and credential theft.
An improper authentication vulnerability (CWE-287) in ZITADEL's external identity provider handler before version 4.15.3 allows remote attackers to perform complete account takeover. When auto-linking by email is enabled, ZITADEL verifies that the local target account has a verified email address but fails to verify if the external provider confirmed ownership of that same email. Attackers can exploit this by registering an unverified account with a victim's email address on a permissive external provider, leading to unauthorized account binding and persistent access.