✓ProveIt
Examples / Report #3249936 Saved analysis

HTTP Request Smuggling Vulnerability Analysis - cURL Security Report

curl · 2025-07-1318.5s analysis · $0.018 in model calls

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

Needs human review

The available evidence does not settle the report. A maintainer should investigate.

curl policy: API misuse
Judgment withdrawn. The answer failed the evidence check.
See 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.

1 · Grounding
grounded
no model · 2 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 2722 tokens · $0.0003
3 · Evidence
1 code snippets
real curl source at 9bdd08b3b22a · 5 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
10759 tokens · 15.3s · $0.0175
5 · Receipts
0 of 1 citations verified
every citation must point at code the judge was shown
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

C1flaw not verifiable

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.

C2location not verifiable

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.

C3trigger supported

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.

C4impact contradicted

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.

E3:0
C5reproduction supported

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)

Full report on HackerOne ↗

# HTTP Request Smuggling Vulnerability Report - cURL ## Summary: cURL does not explicitly reject HTTP requests that contain both Transfer-Encoding and Content-Length headers, which can lead to HTTP request smuggling vulnerabilities (CWE-444) when the request passes through intermediary systems (proxies, load balancers, firewalls) that interpret these conflicting headers differently than the destination server. This inconsistent interpretation allows attackers to potentially smuggle malicious requests past security controls or cause cache poisoning attacks. The vulnerability stems from the `http_req_set_reader()` function in `http.c` which processes Transfer-Encoding headers without validating for the presence of conflicting Content-Length headers. While cURL internally prioritizes Transfer-Encoding over Content-Length when both are present, it does not remove or reject the conflicting Content-Length header, allowing both headers to be sent in the same request. **Note:** This vulnerability analysis was conducted through manual code review of the cURL source code. AI assistance was used to help structure and format this vulnerability report. ## Affected version This vulnerability affects cURL versions that include the current HTTP request handling implementation. Testing was performed on: - **cURL Version:** 8.4.0 (curl-master branch) - **Platform:** Windows 10, Linux Ubuntu 20.04 - **libcurl Version:** 8.4.0 - **Protocols:** HTTP/1.1, HTTP/2 - **Features:** SSL, chunked transfer encoding To check your version, run: ```bash curl -V ``` ## Steps To Reproduce: 1. **Create a test HTTP request with conflicting headers:** ```bash curl -v -X POST \ -H "Transfer-Encoding: chunked" \ -H "Content-Length: 100" \ -d "0\r\n\r\nSMUGGLED_PAYLOAD" \ http://example.com/test ``` 2. **Observe that cURL sends both headers without rejection:** - Monitor the actual HTTP request using `-v` flag - Confirm both `Transfer-Encoding: chunked` and `Content-Length: 100` headers are present - Note that cURL processes the request using chunked encoding while keeping the Content-Length header 3. **Test with a proxy setup to demonstrate smuggling potential:** ```bash # Setup a test proxy that interprets Content-Length first # Then send the conflicting headers through the proxy curl -v --proxy http://test-proxy:8080 \ -H "Transfer- …

Source code

lib/http.clines 111–155 · definition of http_req_complete
111static CURLcode http_req_complete(struct Curl_easy *data,
112 struct dynbuf *r, int httpversion,
113 Curl_HttpReq httpreq);
114static CURLcode http_req_set_reader(struct Curl_easy *data,
115 Curl_HttpReq httpreq, int httpversion,
116 const char **tep);
117static CURLcode http_size(struct Curl_easy *data);
118static CURLcode http_statusline(struct Curl_easy *data,
119 struct connectdata *conn);
120static CURLcode http_target(struct Curl_easy *data, struct connectdata *conn,
121 struct dynbuf *req);
122static CURLcode http_useragent(struct Curl_easy *data);
123#ifdef HAVE_LIBZ
124static CURLcode http_transferencode(struct Curl_easy *data);
125#endif
126
127
128/*
129 * HTTP handler interface.
130 */
131const 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};