Prevent email header injection by never putting raw user input into mail headers, rejecting carriage return and line feed characters in any field that reaches a header, validating the reply-to address as an address, and using a mail library that takes recipients as structured data rather than as text.
Definition
Email header injection is a flaw where an attacker places a line break in a form field and follows it with a header such as Bcc. If your code builds the message by joining strings, the mail library may treat the extra line as a real header and send a copy to the attacker's list. Your server then relays spam or phishing that appears to come from your domain.
Public write-ups describe the same mechanism. A line break ends one header, and whatever follows starts the next.
Where it hides
The classic case is the contact form that sets the Reply-To or Subject from what the visitor typed. Newer plugin bugs show it is not a solved problem. Two 2026 advisories on form plugins describe notification mail where one context validates the reply-to field and another does not neutralize newline characters. The lesson is that every field that can reach a header needs the same treatment, not just the obvious one.
| Field | Reaches a header? | Treatment |
|---|---|---|
| Visitor email | Reply-To, sometimes From | Validate as an address, strip control characters |
| Name | Often in the display name | Strip line breaks, limit length |
| Subject | Subject header | Fixed prefix, reject line breaks |
| Message body | Body only | Fine for headers, still escape for HTML mail |
Steps
- List every form, invite or share feature that sends mail, and mark each field that reaches a header.
- Reject carriage return and line feed in those fields, including encoded forms such as percent encoded values after decoding.
- Do not set From to a visitor value. Send from your own domain and put the visitor in Reply-To.
- Pass recipients to the library as a list, not as part of a header string. Some libraries are naturally resistant because the send call needs an explicit recipient list.
- Cap how many messages one visitor or address can trigger, so a missed bug cannot become a spam run.
- Add a test with a value that contains a line break and a Bcc header, and assert that no extra recipient appears.
A whitelist of allowed characters for names and subjects is stronger than a blocklist, because blocklists miss encodings.
What it costs you if missed
Beyond spam, mail sent from your servers hurts your sending reputation. Mailbox providers watch spam complaints, and a burst of abusive mail from a contact form can affect delivery of your real notifications. See how to keep transactional and marketing email separate.
Where Safeguard fits
Safeguard's code scanning and dependency scanning help surface injection-class patterns in your own code and known advisories in the mail and form libraries you depend on. The free scan is at https://gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen.
Quick check
Does escaping HTML stop header injection?
No. HTML escaping protects the body. Header injection is about line breaks in header fields, so you need a separate check.
Is it safe to let visitors set the From address?
Avoid it. Use your own From address and place the visitor's address in Reply-To after validating it.
Sources
Last reviewed: 19 October 2026.