Join our Newsletter — 33% off our NHI Course
Home› Guides› Email Header Injection Guide: Stop Contact Forms Becoming…
Guide Web & API Security

Email Header Injection Guide: Stop Contact Forms Becoming Spam Relays

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 13 min read
On this page

Email header injection lets anyone who can type into a contact form, newsletter signup or "share this page" feature turn your application into a relay that sends mail under your domain to recipients you never chose. The flaw is simple: user input that ends up in a mail header carries a carriage return and line feed (CRLF), and the mail library or MTA reads the text after it as new headers such as Bcc or a second body. The result is spam and phishing sent from your infrastructure, damage to your sending reputation and SPF/DKIM-aligned mail that receivers trust. This guide is for developers, application security engineers and assessors who own forms and transactional mail. It covers how the flaw works at protocol level (without payloads), where it hides, which library protections exist, how to test for it as a defender and how to detect abuse.

Key takeaways

  • It is CRLF injection in a mail context. MITRE classifies it under CWE-93 (Improper Neutralization of CRLF Sequences), a child of CWE-74, and lists a real case where CRLF in an address or name field created a spam proxy.
  • Headers are the danger zone, not the body. Any user value placed in From, Reply-To, Subject, To, Cc or a display name must never contain CR or LF; the body is safer but can still carry SMTP-level issues if you speak SMTP directly.
  • Modern libraries help if you use their structured APIs. Python's email.policy raises ValueError for CR or LF in a header value and, since Python 3.13, refuses to generate headers that would split; PHP's mail() only warns you to sanitise additional_headers yourself.
  • Never put the visitor's address in From. Send from a fixed, authenticated address you own and place the validated visitor address in Reply-To, which also keeps DMARC alignment intact.
  • Detection lives in the mail logs. A spike in recipients per form submission, unknown Bcc recipients or bounces from addresses nobody entered are the clearest signs that a form is being abused.

How header injection works

An internet message is a block of header lines followed by a blank line and a body. RFC 5322 section 2.2 defines each header field as a field name, a colon and a field body, terminated by CRLF; a body may not contain a bare CR or LF except as part of folding, where a CRLF is followed by a space or tab. Section 3.6 limits To, Cc, Bcc and Subject to at most one occurrence and requires exactly one From. Those rules mean that the only thing separating "data inside the Subject" from "a brand new Bcc header" is a CRLF sequence.

When an application builds headers by concatenating strings, for example taking the name or email address a visitor typed and writing it into a From or Reply-To line, an attacker who submits a value containing an encoded line break can end the intended header and start their own. Typical outcomes are added Bcc or Cc recipients, an overridden Subject, a replaced Content-Type that turns the message into attacker-controlled HTML, or an early blank line that starts a new body. Because the message leaves your server, it inherits your IP reputation and any SPF and DKIM authorisation you have configured.

The OWASP Web Security Testing Guide treats the server-side variant as WSTG-INPV-10, Testing for IMAP/SMTP Injection: applications that talk directly to a mail server can, if input is not sanitised, pass attacker-chosen protocol commands to a back-end server that is often less hardened than the web tier. The listed impacts include evading application restrictions and anti-automation controls, leaking information and relaying spam. See the CRLF Injection and HTTP Response Splitting Guide for the same root cause in HTTP headers, and the Host Header Attacks and Validation Guide for a related flaw that poisons password reset emails.

VariantWhere the input landsWhat an attacker gainsPrimary fix
Header injectionFrom, Reply-To, Subject, To, Cc, display names built by string concatenationExtra recipients (Bcc relay), spoofed content, overridden MIME typeStructured header API that rejects CR and LF; fixed From
SMTP command injectionValues written raw into an SMTP conversation (MAIL FROM, RCPT TO, DATA)Extra envelope recipients, additional messages in one sessionUse a maintained SMTP client library; never hand-write protocol lines
IMAP command injectionWebmail mailbox names, message IDs, search termsReading or altering mailboxes beyond the user's scopeLibrary quoting, allow-list of mailbox identifiers
Sendmail argument injectionExtra parameters passed to a local sendmail binary (for example PHP's additional_params)Changed envelope sender or extra sendmail optionsDo not pass user input to MTA arguments; use a library or API
Body abuse without injectionFree-text message field echoed to a third party ("send to a friend")Phishing text delivered under your brand to arbitrary recipientsOnly send to fixed internal addresses or verified users

Where it hides in real applications

  • Contact and enquiry forms: the visitor's name and email are commonly copied into From or Reply-To. This is the classic spam relay. See the WordPress Security Checklist for keeping form plugins patched.
  • "Email this page" and referral features: both the recipient and a personal message come from the visitor, so even without injection the feature can send arbitrary content to arbitrary people.
  • Account flows: registration, password reset and email change forms put user-supplied addresses into To. Validation gaps here also cause enumeration and token leakage, which the OWASP email verification cheat sheet addresses with single-use, time-limited tokens that are never logged.
  • Notification templates: order confirmations or ticket systems that place a customer-entered subject or reference number into the Subject header.
  • Legacy mail calls: PHP mail() with a hand-built additional_headers string, Perl or shell scripts piping into sendmail, and custom SMTP code written before modern libraries were available.
  • Webmail and mail-adjacent tools: anything that sends IMAP commands built from user input, which is the main target of WSTG-INPV-10.

Library and language protections

The safest design is to let a maintained library build the message from typed fields and never assemble raw header text yourself. How much a library protects you varies, so know what yours actually does.

PlatformDocumented behaviourWhat you still need to do
Python email package (email.policy.default / SMTP)Setting a header raises ValueError if the value contains CR or LF; verify_generated_headers (added in Python 3.13, default True) makes the generator refuse headers that would be parsed as multiple headersUse EmailMessage with policy.default, not the legacy compat32 policy; never set verify_generated_headers to False; catch the exception and reject the request
PHP mail()The manual states that if outside data are used to compose additional_headers, the data should be sanitised so that no unwanted headers can be injected; additional_params is passed through escapeshellcmd(), which stops command execution but still allows extra parameters; since PHP 7.2 headers may be passed as an arrayStrip or reject CR and LF in every header value yourself, pass headers as an array, never pass user input in additional_params; prefer a maintained mail library
Transactional email APIs (HTTP JSON)Recipients and headers are separate JSON fields rather than raw textStill validate addresses and lengths, restrict who can be a recipient, and keep the API key server-side with least privilege
Framework mailersMost provide address objects and header setters rather than raw stringsCheck the framework's documentation for CR and LF handling in custom headers and display names before relying on it

Two points apply everywhere. First, input validation and output handling are separate controls: validate that an email field is an address, and also make sure the code that writes headers neutralises line breaks. See the Input Validation and Output Encoding Guide. Second, OWASP advises using a well-tested address validation library rather than a custom regex, because strict regexes reject valid addresses, and notes that format validation does not prove mailbox access.

Secure design for forms and transactional mail

  1. Inventory every send path. Search code for mail(), sendmail invocations, SMTP client usage and calls to email APIs. Record which fields are user-controlled and which header each lands in.
  2. Fix the sender. Send every form message from a fixed address on a domain you control (for example noreply@ or forms@), authenticated with SPF, DKIM and DMARC. Put the visitor's validated address in Reply-To only.
  3. Fix the recipients. A contact form should only ever deliver to a configured internal address or ticket queue. If a feature must send to a visitor-entered address, require the visitor to be a signed-in, verified user and cap recipients per message.
  4. Reject, do not clean. If any header-bound value contains CR, LF or other control characters, reject the whole submission and log it. Silent stripping hides attacks and can produce surprising results.
  5. Use structured APIs. Build messages with the library's message and address objects, pass headers as typed fields or arrays, and remove any string concatenation of header text.
  6. Constrain lengths and character sets. Cap name, subject and reference fields at sensible lengths and encode non-ASCII subjects as the library requires (PHP's manual notes the subject must satisfy RFC 2047).
  7. Add anti-automation. Rate limit submissions per IP and per session, add bot controls, and alert on high-frequency patterns, as the OWASP email cheat sheet recommends for email flows. See the Bot Management Guide.
  8. Scope the sending credential. Give the application its own SMTP or API credential, restricted to the sending domain and addresses it needs, stored in a secrets manager and rotated. See the Application Email Credentials Guide.

Testing it safely

Treat this as an assurance activity on systems you own or are authorised to test, ideally in a non-production environment with a mail sink so no real recipient ever receives test messages.

  • Code review first: grep for header strings assembled with user input, legacy mail() calls with concatenated headers and any raw SMTP or IMAP protocol writing. Code review finds most cases faster than black-box testing.
  • Unit tests: for each header-bound field, add tests asserting that values containing CR, LF or both are rejected and that the message generated has exactly one of each singleton header (From, To, Subject) as RFC 5322 section 3.6 requires.
  • Dynamic tests: follow WSTG-INPV-10 to identify injection points and assess impact, and confirm in the mail sink that no extra recipients or headers appear. Keep test cases in the tester's methodology rather than in tickets that circulate widely.
  • Requirement mapping: OWASP ASVS 5.0 requirement V1.3.11 states that the application must sanitise user input before passing it to mail systems to protect against SMTP or IMAP injection. Use it as the acceptance criterion for remediation.
  • Regression: keep the CR and LF unit tests in CI so a future refactor or library change cannot silently reintroduce the flaw.

Detection and measurement

Injection that succeeded shows up as mail that looks wrong relative to the form that generated it. Log enough at the application layer to tie each message to a submission.

SignalWhere to lookWhy it matters
Rejected submissions containing CR or LFApplication logs (field name, source IP, timestamp, never the full payload in shared dashboards)Direct evidence of probing
More than the expected number of recipients per form messageMTA or email API logsClassic Bcc relay pattern
Sudden rise in outbound volume from the form sender addressEmail API dashboards, MTA queue metricsAbuse in progress or a bot campaign
Bounces and complaints for addresses nobody enteredBounce processing, feedback loops, DMARC aggregate reportsMail is going to attacker-chosen lists
Blocklisting of the sending IP or domainReputation monitoringLagging indicator that relay abuse already happened

Useful metrics: percentage of send paths using structured APIs (target 100%), number of header-bound fields covered by CR and LF unit tests, form submissions rejected per week for control characters, average recipients per form message (should be exactly the configured number), and mean time from first abuse signal to form disablement.

If you find active abuse, disable the form or feature, rotate the sending credential, review outbound logs for the abuse window, notify your email provider and check blocklists. See the Email Forensics and Header Analysis Guide for reading the headers of the messages that were sent.

Common failure patterns

  • Putting the visitor in From: spoofs your own domain, breaks DMARC alignment and is the field most often concatenated into headers.
  • Validating only on the client: browser-side email checks are bypassed by sending the request directly; validation and neutralisation must be on the server.
  • Stripping "\n" but not "\r": partial filters miss variants. Reject any control character in header values instead of filtering selected ones.
  • Trusting a legacy wrapper: old helper functions that build header strings survive refactors. Python code on the compat32 policy or with verify_generated_headers turned off loses protections the modern policy gives.
  • Open "send to a friend" features: even with perfect header handling, letting anonymous users choose the recipient and the message text creates a phishing relay.
  • Over-privileged sending credentials: an API key that can send as any address on the domain turns a form flaw into domain-wide spoofing.

Framework mapping

FrameworkReferenceRelevance
MITRE CWECWE-93 Improper Neutralization of CRLF Sequences (child of CWE-74)Root weakness class
OWASP ASVS 5.0V1.3.11Sanitise user input passed to mail systems against SMTP or IMAP injection
OWASP WSTGWSTG-INPV-10 Testing for IMAP/SMTP InjectionTest procedure for assessors
NIST SP 800-53 Rev 5SI-10 Information Input Validation; SI-4 System MonitoringValidation of inputs and monitoring of outbound abuse
ISO/IEC 27001:2022 Annex AA.8.28 Secure codingSecure coding practice for mail-sending code

Practitioner checklist

  • List every code path that sends mail and mark each user-controlled field and the header it reaches.
  • Send all form mail from a fixed authenticated address; put the visitor's validated address in Reply-To only.
  • Restrict recipients to configured internal addresses unless the sender is a verified, signed-in user.
  • Reject any submission with CR, LF or other control characters in a header-bound field, and log the rejection.
  • Replace string-built headers with structured library APIs; on Python use policy.default and keep verify_generated_headers on.
  • Never pass user input to sendmail arguments or PHP's additional_params.
  • Add CR and LF unit tests per field and keep them in CI; use ASVS V1.3.11 as the acceptance criterion.
  • Rate limit and bot-protect forms, and alert on recipients per message and outbound volume.
  • Scope, vault and rotate the application's sending credential.

Standards and references

Related NHI Mgmt Group resources: CRLF Injection and HTTP Response Splitting Guide · Host Header Attacks and Validation Guide · Application Email Credentials Guide · Email Security Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org