HTTP Request Smuggling Vulnerability Analysis - cURL Security Report
What the report claims
cURL does not reject HTTP requests containing both Transfer-Encoding and Content-Length headers, leading to potential HTTP request smuggling when intermediaries interpret these headers inconsistently.
Compare with curl's recorded outcome
Labeled AI slop
curl's maintainer lists this report as AI slop
Shown for comparison after analysis. The pipeline did not see this label.
ProveIt's finding
The available evidence does not settle the report. A maintainer should investigate.
curl policy: API misuseSee the withdrawn model reasoning
The following reasoning failed the citation check and does not support the final finding.
- The report demonstrates the issue by explicitly passing both headers via curl's -H command-line option, which is the user deliberately constructing a request with conflicting headers. This is API misuse, not a cURL vulnerability.
- RFC 7230 Section 3.3.3 establishes precedence (Transfer-Encoding over Content-Length) but does not forbid a client from sending both headers. The smuggling risk exists in intermediaries that violate the RFC precedence rules, not in the client.
- cURL's command-line tool and libcurl API are designed to send whatever headers the application/user specifies. Validating or rejecting header combinations would break legitimate use cases and exceed the API's documented behavior.
- The project policy explicitly lists 'API misuse' as not a security issue: 'If a reported issue only triggers by an application using the API in a way that is not documented to work or even documented to not work, it is probably not going to be considered a security problem.'
How this analysis ran 5 claims · 0 citations verified
Evidence check: judge quoted an external source that does not say that (https://datatracker.ietf.org/doc/html/rfc7230.html)
Checked against curl master on 2025-07-13 (9bdd08b3b22a). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Inspect the withdrawn draft reply
This draft belongs to the withdrawn judgment. It may contain unsupported claims.
Thank you for the detailed report. However, this is not a cURL vulnerability. The reproduction steps show you explicitly passing both Transfer-Encoding and Content-Length headers via -H options — this is your application choosing to send conflicting headers. RFC 7230 Section 3.3.3 gives Transfer-Encoding precedence over Content-Length but does not forbid sending both; the smuggling risk lies in intermediaries that violate this precedence, not in the client. cURL's API sends whatever headers the caller sets, and the project policy classifies API misuse as not a security issue.
Inspect all claims and source code 5 claims · 1 code excerpts
This model judgment was withdrawn. The claim assessments below are preserved for inspection and may be wrong.
Report claims
cURL does not explicitly reject HTTP requests that contain both Transfer-Encoding and Content-Length headers
Read the reasoning
The provided source code only shows function declarations (lines 111-155 of lib/http.c), not the implementation of http_req_set_reader() or http_req_complete(). The deterministic checks confirm these functions exist at the revision, but their logic is not visible. Therefore, I cannot verify whether cURL internally prioritizes Transfer-Encoding over Content-Length or whether it rejects requests with both headers.
The flaw is in the http_req_set_reader() function in http.c
Read the reasoning
The report locates the flaw in http_req_set_reader() in http.c. While the deterministic checks confirm this function exists at the revision, its implementation is not in the provided source code (only the forward declaration at line 114-116). Cannot verify the claim about this specific function's behavior.
An attacker can send a request with both Transfer-Encoding: chunked and Content-Length: headers
Read the reasoning
The reproduction steps show the user explicitly passing both headers via command-line options (-H "Transfer-Encoding: chunked" -H "Content-Length: 100"). cURL's command-line tool and libcurl API allow applications to set arbitrary headers. This is not a flaw in cURL but a deliberate choice by the user/application constructing the request.
This can lead to HTTP request smuggling vulnerabilities when the request passes through intermediary systems that interpret these conflicting headers differently than the destination server
Read the reasoning
The RFC establishes clear precedence rules (Transfer-Encoding over Content-Length) but does not forbid sending both headers. The smuggling vulnerability described arises from intermediaries (proxies, load balancers) that violate the RFC by interpreting headers inconsistently, not from the client sending both headers per the precedence rules. cURL as a client follows the RFC by allowing the application to set headers; the vulnerability lies in non-compliant intermediaries.
Use curl with -H "Transfer-Encoding: chunked" -H "Content-Length: 100" -d "0\r\n\r\nSMUGGLED_PAYLOAD" to reproduce
Read the reasoning
The reproduction command demonstrates that a user can explicitly pass both headers via -H options. This confirms the user can construct such a request, but it demonstrates API usage (deliberately setting conflicting headers), not a cURL vulnerability.
What the report says about other projects
confirmed RFC 7230 Section 3.3.3 defines message body length precedence: Transfer-Encoding (chunked as final encoding) takes precedence over Content-Length
“The length of a message body is determined by one of the following (in order of precedence): [...] 3. If a Transfer-Encoding header field is present and the chunked transfer coding (Section 4.1) is the final encoding, the message body [...]” source
confirmed RFC 7230 requires servers to reject requests where Transfer-Encoding is present but chunked is not the final encoding
“If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the final encoding, the message body length cannot be determined reliably; the server MUST respond with the 400 (Bad Request) status code and then close the connection.” source
Read the original report (excerpt)
Source code
| 111 | static CURLcode http_req_complete(struct Curl_easy *data, |
| 112 | struct dynbuf *r, int httpversion, |
| 113 | Curl_HttpReq httpreq); |
| 114 | static CURLcode http_req_set_reader(struct Curl_easy *data, |
| 115 | Curl_HttpReq httpreq, int httpversion, |
| 116 | const char **tep); |
| 117 | static CURLcode http_size(struct Curl_easy *data); |
| 118 | static CURLcode http_statusline(struct Curl_easy *data, |
| 119 | struct connectdata *conn); |
| 120 | static CURLcode http_target(struct Curl_easy *data, struct connectdata *conn, |
| 121 | struct dynbuf *req); |
| 122 | static CURLcode http_useragent(struct Curl_easy *data); |
| 123 | #ifdef HAVE_LIBZ |
| 124 | static CURLcode http_transferencode(struct Curl_easy *data); |
| 125 | #endif |
| 126 | |
| 127 | |
| 128 | /* |
| 129 | * HTTP handler interface. |
| 130 | */ |
| 131 | const struct Curl_handler Curl_handler_http = { |
| 132 | "http", /* scheme */ |
| 133 | Curl_http_setup_conn, /* setup_connection */ |
| 134 | Curl_http, /* do_it */ |
| 135 | Curl_http_done, /* done */ |
| 136 | ZERO_NULL, /* do_more */ |
| 137 | Curl_http_connect, /* connect_it */ |
| 138 | ZERO_NULL, /* connecting */ |
| 139 | ZERO_NULL, /* doing */ |
| 140 | ZERO_NULL, /* proto_getsock */ |
| 141 | Curl_http_getsock_do, /* doing_getsock */ |
| 142 | ZERO_NULL, /* domore_getsock */ |
| 143 | ZERO_NULL, /* perform_getsock */ |
| 144 | ZERO_NULL, /* disconnect */ |
| 145 | Curl_http_write_resp, /* write_resp */ |
| 146 | Curl_http_write_resp_hd, /* write_resp_hd */ |
| 147 | ZERO_NULL, /* connection_check */ |
| 148 | ZERO_NULL, /* attach connection */ |
| 149 | Curl_http_follow, /* follow */ |
| 150 | PORT_HTTP, /* defport */ |
| 151 | CURLPROTO_HTTP, /* protocol */ |
| 152 | CURLPROTO_HTTP, /* family */ |
| 153 | PROTOPT_CREDSPERREQUEST | /* flags */ |
| 154 | PROTOPT_USERPWDCTRL |
| 155 | }; |