If you're using curl or libcurl for HTTP(S) transfers in your application, you might be at risk for information disclosure due to a bug discovered and tracked as CVE-2023-28322. This vulnerability is specifically related to how curl handles reusing "easy handles" when you switch HTTP methods — especially from PUT to POST. In this long read, we’ll break down what the issue is, provide easy-to-follow code snippets, explain how the exploit works, and point you to original resources for further details.
⚠️ Note: This issue affects all versions of curl < 8.1..
In Simple Terms
- When you use libcurl to do an HTTP PUT with a custom read callback (CURLOPT_READFUNCTION), and then, using the same handle (CURL *easy_handle), you later perform a POST using CURLOPT_POSTFIELDS, curl might use your old callback anyway!
- This mixup can cause your application to send the wrong data, or worse, use data from freed memory, leading to information leaks or even crashes.
Versions: All before 8.1.
- Scenario: Reusing a handle that did a PUT (with a read callback) for a POST (with POST fields)
How Does It Happen?
When you use curl or libcurl, you typically reuse CURL *handle objects to keep things efficient. Normally, you can safely switch from one HTTP method to another. But, when you:
Later switch to a POST using CURLOPT_POSTFIELDS, without clearing the callback
libcurl's logic forgets to stop using your read callback. That means for your next HTTP POST, instead of sending the data from POSTFIELDS, it may call your old read callback — possibly referencing stale, wrong, or even freed memory!
Diagram of Handle Reuse Error
+----------------+ 1. PUT (using read callback)
| Setup handle | ------------------------------->
| | 2. Switch to POST
+----------------+ <-------------------------------
\
Uses old read function
Sends wrong or stale data in POST
Let’s see how this might bite you in real code
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
size_t my_readfunc(void *ptr, size_t size, size_t nmemb, void *userdata) {
const char *put_data = (const char *)userdata;
size_t len = strlen(put_data);
if (len > size * nmemb)
len = size * nmemb;
memcpy(ptr, put_data, len);
return len;
}
int main(void) {
CURL *curl = curl_easy_init();
if (!curl) return 1;
// First: do a PUT request with a read callback
const char *put_data = "SensitiveDataFromPUT!";
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/upload";);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_readfunc);
curl_easy_setopt(curl, CURLOPT_READDATA, put_data);
// ... perform PUT
curl_easy_perform(curl);
// Now: do a POST request with POSTFIELDS (expecting the callback is NOT used)
const char *post_data = "NonSensitiveData";
curl_easy_setopt(curl, CURLOPT_UPLOAD, L); // Reset to not upload
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
// ... perform POST
curl_easy_perform(curl);
curl_easy_cleanup(curl);
return ;
}
What’s the problem?
During the POST, instead of sending "NonSensitiveData", curl might use my_readfunc again — leaking "SensitiveDataFromPUT!" or whatever memory put_data pointed to. If that memory is freed, this could also lead to a crash or more severe issues.
Exploit Scenario
Imagine an attacker can trigger a PUT with sensitive data via your application (through some admin action or misdirected upload), and then, almost immediately, cause your app to POST something else. If your app exposed the read callback (maybe a buffer in memory with keys, tokens, or secrets), you might send out this sensitive information to an unintended location!
Official Fix
- Patch/Upgrade: The vulnerability is fixed in curl version 8.1. and later.
- Downloads: https://curl.se/download.html
> Changelog entry:
> "libcurl: fix transfer when switching from PUT to POST with POSTFIELDS CVE-2023-28322"
Workarounds
- Don’t reuse handles: Either cleanup and re-init handles between different request types, or always set CURLOPT_READFUNCTION to NULL before switching to POST with CURLOPT_POSTFIELDS.
curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
`
---
## References & Further Reading
- Official Curl Advisory:
CVE-2023-28322 at curl.se
- Commit Fix:
GitHub commit
- CVE Details:
NVD CVE-2023-28322
- Curl Changelog:
https://curl.se/changes.html#8_1_
---
## Conclusion: What Should You Do?
- Upgrade to curl/libcurl 8.1. or later.
- Consider not reusing handles across radically different HTTP methods, or always reset all callbacks and data pointers before new transfers.
- Review your application for any unsafe patterns and patch immediately if you’re using affected versions.
- If you provide a library or component that wraps libcurl, make your users aware!
Stay safe, and always keep your dependencies up to date!
---
If you found this post helpful, feel free to share or check the original resources above for the latest security advisories.
Timeline
Published on: 05/26/2023 21:15:00 UTC
Last modified on: 06/16/2023 16:40:00 UTC