HexBrain

curl · Report #1101882

CVE-2021-22876: Automatic referer leaks credentials

Validstatus
lowseverity
5upvotes
30 Apr 2021disclosed

How it was found

Summary:

When using the --referer ';auto' feature the current URL is copied as-is to the referrer header of the subsequent request. The recommendation [1] is to strip these (along with the URL fragment). I can imagine this may, in rare cases, result in unwanted/unexpected disclosure of credentials (e.g. them appearing in 3rd party web server logs), though the overall chances seem low (also considering that ';auto', by hunch, is likely not a widely used curl feature).

[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer#directives

Steps To Reproduce:

$ curl -svLe ';auto' 'https://user:[email protected]#frag'  2>&1 >/dev/null | grep -i Referer:

Supporting Material/References:

$ curl -V                                                                                                
curl 7.64.1 (x86_64-apple-darwin19.0) libcurl/7.64.1 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.39.2
Release-Date: 2019-03-27
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS GSS-API HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets

Patch that fixes it

diff --git a/lib/transfer.c b/lib/transfer.c
index c3b2d11a2..f63aadbaf 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -1567,6 +1567,9 @@ CURLcode Curl_follow(struct Curl_easy *data,
       data->state.followlocation++; /* count location-followers */
 
       if(data->set.http_auto_referer) {
+        CURLU *h;
+        char *url;
+
         /* We are asked to automatically set the previous URL as the referer
            when we get the next URL. We pick the ->url field, which may or may
            not be 100% correct */
@@ -1576,7 +1579,40 @@ CURLcode Curl_follow(struct Curl_easy *data,
           data->change.referer_alloc = FALSE;
         }
 
-        data->change.referer = strdup(data->change.url);
+        /* Make a copy of the URL without the crenditals and fragment */
+        h = curl_url();
+        if(!h)
+          return CURLE_OUT_OF_MEMORY;
+
+        uc = curl_url_set(h, CURLUPART_URL, data->change.url, 0);
+        if(uc) {
+          curl_url_cleanup(h);
+          return CURLE_OUT_OF_MEMORY;
+        }
+        uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
+        if(uc) {
+          curl_url_cleanup(h);
+          return CURLE_OUT_OF_MEMORY;
+        }
+        uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
+        if(uc) {
+          curl_url_cleanup(h);
+          return CURLE_OUT_OF_MEMORY;
+        }
+        uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
+        if(uc) {
+          curl_url_cleanup(h);
+          return CURLE_OUT_OF_MEMORY;
+        }
+        uc = curl_url_get(h, CURLUPART_URL, &url, 0);
+        if(uc) {
+          curl_url_cleanup(h);
+          return CURLE_OUT_OF_MEMORY;
+        }
+
+        curl_url_cleanup(h);
+
+        data->change.referer = url;
         if(!data->change.referer)
           return CURLE_OUT_OF_MEMORY;
         data->change.referer_alloc = TRUE; /* yes, free this later */

I'm ready to continue this in a public PR if it seems more fitting.

Impact

The best I can think of is if an attacker gets hold of web server logs that includer referrer info with credentials leaked into them. It's a privacy/sensitive info-leak vulnerability at best. Can't readily think of a way to actively exploit this.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original