HexBrain

curl · Report #3481595

SMTP CRLF Injection & Protocol Desynchronization in libcurl

N/Astatus
mediumseverity
16upvotes
29 Dec 2025disclosed

How it was found

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

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:

[!] 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.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original