WSS
Web Specification Studio Home
On this page
SecurityRequiredUpdated

Email Header Injection & CRLF Neutralization

Prevent SMTP and RFC 5322 header injection vulnerabilities by neutralizing CRLF control characters and using typed mail serialization libraries.

What it is

Email Header Injection (CWE-93) is a critical security vulnerability that occurs when untrusted user input containing carriage return (\r / %0D) or line feed (\n / %0A) control characters is concatenated into email header fields (such as Subject, From, To, Reply-To, or custom headers).

Because RFC 5322 delimits header lines using CRLF (\r\n), an attacker can inject newline characters to terminate the existing header and append arbitrary headers - such as Bcc:, Cc:, or Content-Type: - or inject a double CRLF (\r\n\r\n) to split the header section early and overwrite the entire message body:

// Attacker Input in "Subject" form field:
Project Status\r\nBcc: [email protected], [email protected]\r\n\r\nClick here for malware: https://evil.com

// Resulting Serialized Message:
Subject: Project Status
Bcc: [email protected], [email protected]

Click here for malware: https://evil.com
[Original body follows as attacker-controlled text...]

Why it matters

  • Spam Relaying & Botnet Weaponization: Attackers abuse vulnerable contact forms and password reset endpoints to inject thousands of unauthorized recipient addresses in Bcc: headers, transforming your trusted email servers into an automated spam/phishing relay.
  • Immediate Domain Blocklisting: When your domain dispatches injected phishing emails with valid SPF and DKIM signatures, your domain is instantly added to global DNS blocklists (Spamhaus, Invaluement, Barracuda).
  • Phishing & Brand Impersonation: Attackers can inject a rogue Reply-To: header or split the body to deliver forged transactional notifications that appear authentic to customers.

How to implement

1. Never construct email headers via string concatenation. Do not use string formatting, template strings, or string concatenation to build raw RFC 5322 messages. Use a standard, security-hardened mail library (e.g., Nodemailer in Node.js, email.message in Python, or net/smtp in Go) that automatically validates and encodes header values.

2. Strictly sanitize and validate all header inputs: Enforce validation rules on all user-supplied strings intended for headers:

  • Reject any input containing ASCII control characters \r (0x0D), \n (0x0A), or null bytes (\0).
  • If an input contains newline characters, fail with an HTTP 400 validation error rather than attempting to strip characters.
// Strict Header Input Validator
function validateHeaderField(value: string, fieldName: string): string {
  if (/[\r\n\0]/.test(value)) {
    throw new Error(`Security Exception: Header injection detected in ${fieldName}`);
  }
  return value.trim();
}

3. Enforce strict address parsing for recipient fields: When parsing recipient addresses (To, Cc, Bcc), use RFC 5322 address parsers that validate mailbox syntax rather than accepting arbitrary strings:

import email.utils

# Validate and format single clean address
name, addr = email.utils.parseaddr(user_input_email)
if not addr or '@' not in addr or '\n' in addr or '\r' in addr:
    raise ValueError("Invalid email address syntax")

4. Sanitize Attachment Filenames: Ensure attachment filenames do not contain path traversal characters (../) or raw newline characters in the Content-Disposition header.

Common mistakes

  • Stripping \n while Forgetting \r: Only replacing \n allows standalone \r characters to pass through, which certain MTAs normalize back to \r\n.
  • Relying on Client-Side Form Validation Alone: HTML <input type="text"> fields strip newlines in browsers, but attackers easily bypass browser UI using direct HTTP API requests.
  • Trusting Internal Microservice Headers: Assuming that internal API payloads or queue messages are pre-sanitized.
  • Overlooking Encoded Newlines: Failing to decode URL-encoded (%0A, %0D) or Unicode newline variants (\u0085, \u2028) before validation.

Verification

1. Automated Security Fuzzing Test Suite: Execute automated test suites that submit payloads containing CRLF sequences across all form inputs:

# Verify API rejects header injection attempts with HTTP 400
curl -X POST https://api.example.com/contact \
  -H "Content-Type: application/json" \
  -d '{"name": "Attacker", "subject": "Test\r\nBcc: [email protected]", "message": "hello"}' -i
# Must return: HTTP/1.1 400 Bad Request

2. Unit test mail serializer: Verify that your mail generation framework throws an exception when attempting to set a header containing newline characters.

Related topics

Sources & further reading