✓ProveIt
Examples / Report #1704017 Saved analysis

CVE-2022-32221: POST following PUT confusion

curl · 2022-09-1811.7s analysis · $0.011 in model calls

What the report claims

A bug causes libcurl to perform an HTTP PUT when the user intends an HTTP POST, leading to potential information disclosure and use-after-free vulnerabilities.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2022-32221 POST following PUT confusion

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.

Why this finding?
  • The central claim (C1) about CURLOPT_POST vs CURLOPT_UPLOAD interaction cannot be evaluated because the provided source code snippets only show function entry points (curl_easy_perform, curl_easy_setopt), not the option processing logic in Curl_vsetopt or the HTTP method selection in easy_perform.
  • All five claims depend on code not included in the provided context. The deterministic checks only confirm option symbols exist, not their behavioral interaction.
  • The report references a known issue (#9507) and provides a concrete reproduction case, making the claim plausible, but the provided evidence is insufficient to confirm or refute it.
What still needs checking
  • The implementation of Curl_vsetopt (in lib/setopt.c) showing how CURLOPT_POST and CURLOPT_UPLOAD are handled
  • The implementation of easy_perform (in lib/easy.c) showing HTTP method selection logic
  • Any code that sets data->set.upload or data->set.httpreq based on these options
How this analysis ran 5 claims · 0 citations verified

Checked against curl master on 2022-09-18 (6de7322c03d5). Test 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 · 2009 tokens · $0.0002
3 · Evidence
2 code snippets
real curl source at 6de7322c03d5 · 6 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
6934 tokens · 8.4s · $0.0106
5 · Receipts
0 of 0 citations verified
every citation must point at code the judge was shown
Review a draft reply to the reporter

Edit and verify before sending.

Thank you for the detailed report and reproduction case. To evaluate this, we need to see the option handling code that processes CURLOPT_POST and CURLOPT_UPLOAD (in lib/setopt.c, Curl_vsetopt) and the HTTP method selection logic in lib/easy.c (easy_perform). The provided snippets only show the public API entry points. Could you point to the specific lines where these options interact, or should we fetch those files for review?

Inspect all claims and source code 5 claims · 2 code excerpts

Report claims

C1flaw not verifiable

When CURLOPT_POST is set but CURLOPT_UPLOAD is also set, libcurl performs an HTTP PUT instead of the intended POST

Read the reasoning

The provided source code only shows curl_easy_perform and curl_easy_setopt entry points (lib/easy.c:769-772, lib/setopt.c:3122-3136). The actual logic that resolves CURLOPT_POST vs CURLOPT_UPLOAD and selects the HTTP method is in Curl_vsetopt (called from curl_easy_setopt) and easy_perform (called from curl_easy_perform), which are not included in the provided snippets. Without seeing the option handling and request preparation code, I cannot verify whether setting both options causes a PUT instead of POST.

C2location not verifiable

The issue occurs during the request preparation phase before the transfer is sent

Read the reasoning

The claim states the issue occurs 'during the request preparation phase before the transfer is sent' but the provided code does not include the request preparation logic (easy_perform or the HTTP method selection code). The only perform-related code shown is the trivial wrapper curl_easy_perform at lib/easy.c:769-772.

C3trigger not verifiable

Setting both CURLOPT_POST and CURLOPT_UPLOAD in the same easy handle causes the unintended PUT

Read the reasoning

Same as C1: the trigger condition (setting both CURLOPT_POST and CURLOPT_UPLOAD) is described, but the code that processes these options and decides the HTTP method is not in the provided snippets. The curl_easy_setopt function at lib/setopt.c:3122-3136 only shows the varargs dispatch to Curl_vsetopt.

C4impact not verifiable

Sensitive data from CURLOPT_READDATA may be sent to an unintended host, and freed data may be accessed after free

Read the reasoning

The impact claim (sensitive data from CURLOPT_READDATA sent to unintended host, use-after-free) depends entirely on C1 being true. Since C1 cannot be verified from the provided code, this impact claim also cannot be verified. The deterministic checks only confirm the option symbols exist, not their interaction behavior.

C5reproduction not verifiable

The provided test program demonstrates the bug by sending a PUT to host1.com with secret data when a POST to host2.com was intended

Read the reasoning

The reproduction code is provided in the report, but without the curl internal logic that handles CURLOPT_POST and CURLOPT_UPLOAD, I cannot confirm the test program would demonstrate the described bug. The provided curl source does not include the relevant decision points.

Read the original report (excerpt)

Full report on HackerOne ↗

## Summary: The bug I submitted at https://github.com/curl/curl/issues/9507 can have at least a few unintended security issues: - Information Disclosure: this bug causes an HTTP PUT to occur when the user intends for an HTTP POST to occur. The user, who intended an HTTP POST, expects the POSTed information to come from CURLOPT_POSTFIELDS. However, as an HTTP PUT is performed instead, the data that is PUT comes from a buffer specified in CURLOPT_READDATA, which may be sensitive information intended for an entirely different host (host1.com below). If CURLOPT_READDATA is not specified, this data could come from stdin! - Use after free: using the description above, if the user had already freed the data specified in CURLOPT_READDATA, then the unintended HTTP PUT (which was intended to be an HTTP POST) would attempt to read the freed data specified in CURLOPT_READDATA. ## Steps To Reproduce: The following code is similar to the code I posted at https://github.com/curl/curl/issues/9507, but now highlights the potential security issues (which I did not think wise to disclose on GitHub): ``` #include <stdio.h> #include <string.h> #include <curl/curl.h> typedef struct { char *buf; size_t len; } put_buffer; static size_t put_callback(char *ptr, size_t size, size_t nmemb, void *stream) { put_buffer *putdata = (put_buffer *)stream; size_t totalsize = size * nmemb; size_t tocopy = (putdata->len < totalsize) ? putdata->len : totalsize; memcpy(ptr, putdata->buf, tocopy); putdata->len -= tocopy; putdata->buf += tocopy; return tocopy; } int main() { CURL *curl = NULL; put_buffer pbuf = {}; char *otherdata = "This is some other data"; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); // PUT curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_READFUNCTION, put_callback); pbuf.buf = strdup("This is highly secret and sensitive data"); pbuf.len = strlen(pbuf.buf); curl_easy_setopt(curl, CURLOPT_READDATA, &pbuf); curl_easy_setopt(curl, CURLOPT_INFILESIZE, pbuf.len); curl_easy_setopt(curl, CURLOPT_URL, "http://host1.com/putsecretdata"); curl_easy_perform(curl); // Without this line, a PUT instead of a POST will be sent below (this is a bug in libcurl) //curl_easy_setopt(curl, CURLOPT_UPLOAD, 0L); // Without this line, the POST below …

Source code

lib/easy.clines 769–772 · definition of curl_easy_perform
769CURLcode curl_easy_perform(struct Curl_easy *data)
770{
771 return easy_perform(data, FALSE);
772}
lib/setopt.clines 3122–3136 · definition of curl_easy_setopt
3122CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
3123{
3124 va_list arg;
3125 CURLcode result;
3126
3127 if(!data)
3128 return CURLE_BAD_FUNCTION_ARGUMENT;
3129
3130 va_start(arg, tag);
3131
3132 result = Curl_vsetopt(data, tag, arg);
3133
3134 va_end(arg);
3135 return result;
3136}