Email header and body injection

Email header and body injection

Description

Concatenating user input directly into an email header may let CR/LF characters introduce new headers or body content. Building password-reset links or transactional email bodies from untrusted URL or host values can also let an attacker alter the message.

Potential impact

  • Attackers may insert phishing links or abuse password-reset flows.
  • Users may mistake manipulated messages for trusted service email.

Remediation

  • Read the email's base URL and hostname from trusted server configuration. Generate reset tokens on the server too.
  • Reject CR/LF in header values and validate recipient addresses against both address syntax and permitted business use. Handle text and links in HTML bodies according to their output context.
  • Distinguish SMTP recipients from displayed message headers and select the correct recipients.

Examples

These excerpts compare only construction of the To header. The actual SMTP recipients are determined by the separate to argument to smtp.SendMail. Authentication, transport protection and send-error handling are omitted. Replace the fixed address in the revised example with the actual approved recipient.

Before

go
email := r.FormValue("email")
body := "Subject: reset\r\nTo: " + email + "\r\n\r\nhello"
smtp.SendMail(addr, nil, from, to, []byte(body))

After

go
body := "Subject: reset\r\nTo: user@example.com\r\n\r\nhello"
smtp.SendMail(addr, nil, from, to, []byte(body))

Explanation:

  • Before: Unvalidated email input is concatenated into the To header, so CR/LF input may alter headers or body content.
  • After: This example does not construct the To header from user input. Dynamic recipients still need validation, and reset-URL trust must be enforced separately.

References