CVE-2021-22923: Metalink download sends credentials
What the report claims
When compiled with libmetalink and used with --metalink and --user, curl sends credentials to any host referenced in a metalink file, even without TLS, potentially leaking credentials intended for a specific target.
Compare with curl's recorded outcome
Known vulnerability
A real vulnerability: CVE-2021-22923 Metalink download sends credentials
Shown for comparison after analysis. The pipeline did not see this label.
ProveIt's finding
The available evidence does not settle the report. A maintainer should investigate.
Why this finding?
- The report describes a concrete and plausible attack scenario: metalink files referencing third-party hosts could receive credentials provided for the original target.
- However, the provided source code (only lib/urldata.h lines 122-199) does not contain the metalink parsing logic, credential handling for metalink transfers, or the CURLOPT_LOCATIONTRUSTED implementation needed to verify or contradict the claims.
- All six claims are not_verifiable against the given code snippets. A human reviewer needs to examine the metalink implementation (likely lib/metalink.c) and the credential propagation logic.
What still needs checking
- Source code for metalink handling (likely lib/metalink.c)
- Credential propagation logic when following metalink references
- Implementation of CURLOPT_LOCATIONTRUSTED and whether it applies to metalink
How this analysis ran 6 claims · 0 citations verified
Checked against curl master on 2021-05-30 (1c1d9f1affbd). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Review a draft reply to the reporter
Edit and verify before sending.
Thank you for the report. The metalink credential forwarding behavior you describe is plausible and concerning. However, the code snippets provided for triage (only lib/urldata.h) do not contain the metalink parsing or credential handling logic needed to verify the claims. Could you point to the specific source files (e.g., lib/metalink.c) and functions where credentials are applied to metalink-referenced URLs? That would allow us to confirm whether CURLOPT_LOCATIONTRUSTED or similar protections are missing for metalink transfers.
Inspect all claims and source code 6 claims · 1 code excerpts
Report claims
curl sends credentials to any host referenced in a metalink file, even without TLS
Read the reasoning
The claim describes metalink credential forwarding behavior, but the provided source code (lib/urldata.h lines 122-199) only shows typedefs and includes. The metalink parsing and credential handling implementation (likely in lib/metalink.c or similar) is not provided, so the claim cannot be verified against the given code.
credentials intended for a target site may end up being sent to outside hosts
Read the reasoning
Same as C1: the code that handles CURLOPT_USERPWD and CURLOPT_HTTPAUTH in the context of metalink transfers is not in the provided snippets.
the leak occurs for http and ftp protocols without transport layer security
Read the reasoning
While deterministic checks confirm http and ftp symbols exist at this revision, the credential leak logic for those protocols during metalink processing is not shown in the provided code.
the behavior is unexpected and insecure
Read the reasoning
The claim references CURLOPT_LOCATIONTRUSTED behavior for metalink, but the implementation of that option and its interaction with metalink is not in the provided source.
credentials can be seen by the target host and anyone in man in the middle position
Read the reasoning
This describes the consequence of the alleged flaw. The code path that would send Authorization headers to metalink-referenced hosts is not provided.
the leak occurs when using --metalink with --user and a metalink file referencing different hosts
Read the reasoning
The CURLOPT_METALINK option handling and its interaction with --user credentials is not shown in the provided source snippet.
What the report says about other projects
not addressed CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) might be a more accurate CWE
Read the original report
Source code
| 122 | typedef CURLcode (*Curl_datastream)(struct Curl_easy *data, |
| 123 | struct connectdata *conn, |
| 124 | int *didwhat, |
| 125 | bool *done, |
| 126 | int select_res); |
| 127 | #endif |
| 128 | |
| 129 | #include "mime.h" |
| 130 | #include "imap.h" |
| 131 | #include "pop3.h" |
| 132 | #include "smtp.h" |
| 133 | #include "ftp.h" |
| 134 | #include "file.h" |
| 135 | #include "vssh/ssh.h" |
| 136 | #include "http.h" |
| 137 | #include "rtsp.h" |
| 138 | #include "smb.h" |
| 139 | #include "mqtt.h" |
| 140 | #include "wildcard.h" |
| 141 | #include "multihandle.h" |
| 142 | #include "quic.h" |
| 143 | #include "c-hyper.h" |
| 144 | |
| 145 | #ifdef HAVE_GSSAPI |
| 146 | # ifdef HAVE_GSSGNU |
| 147 | # include <gss.h> |
| 148 | # elif defined HAVE_GSSAPI_GSSAPI_H |
| 149 | # include <gssapi/gssapi.h> |
| 150 | # else |
| 151 | # include <gssapi.h> |
| 152 | # endif |
| 153 | # ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H |
| 154 | # include <gssapi/gssapi_generic.h> |
| 155 | # endif |
| 156 | #endif |
| 157 | |
| 158 | #ifdef HAVE_LIBSSH2_H |
| 159 | #include <libssh2.h> |
| 160 | #include <libssh2_sftp.h> |
| 161 | #endif /* HAVE_LIBSSH2_H */ |
| 162 | |
| 163 | #define READBUFFER_SIZE CURL_MAX_WRITE_SIZE |
| 164 | #define READBUFFER_MAX CURL_MAX_READ_SIZE |
| 165 | #define READBUFFER_MIN 1024 |
| 166 | |
| 167 | /* The default upload buffer size, should not be smaller than |
| 168 | CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in |
| 169 | a write callback. |
| 170 | |
| 171 | The size was 16KB for many years but was bumped to 64KB because it makes |
| 172 | libcurl able to do significantly faster uploads in some circumstances. Even |
| 173 | larger buffers can help further, but this is deemed a fair memory/speed |
| 174 | compromise. */ |
| 175 | #define UPLOADBUFFER_DEFAULT 65536 |
| 176 | #define UPLOADBUFFER_MAX (2*1024*1024) |
| 177 | #define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE |
| 178 | |
| 179 | #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU |
| 180 | #define GOOD_EASY_HANDLE(x) \ |
| 181 | ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) |
| 182 | |
| 183 | /* the type we use for storing a single boolean bit */ |
| 184 | #ifdef _MSC_VER |
| 185 | typedef bool bit; |
| 186 | #define BIT(x) bool x |
| 187 | #else |
| 188 | typedef unsigned int bit; |
| 189 | #define BIT(x) bit x:1 |
| 190 | #endif |
| 191 | |
| 192 | #ifdef HAVE_GSSAPI |
| 193 | /* Types needed for krb5-ftp connections */ |
| 194 | struct krb5buffer { |
| 195 | void *data; |
| 196 | size_t size; |
| 197 | size_t index; |
| 198 | BIT(eof_flag); |
| 199 | }; |