curl · Report #3646914
ignoring 'options' when doing connection reuse
How it was found
libcurl contains a significant logic flaw in its connection pool matching mechanism. When a transfer specifies a required authentication policy—such as a specific SASL mechanism (e.g., ;AUTH=GSSAPI) or a restricted set of SSH authentication types (CURLOPT_SSH_AUTH_TYPES)—libcurl fails to verify these constraints against existing connections in its pool.
This leads to a Silent Policy Bypass: a transfer requesting a high-security authentication method will incorrectly reuse a pooled connection established with a different (and potentially weaker) method, provided the basic credentials (username/password) match. The developer's explicit security instructions are discarded, and the transfer proceeds under the security context of a previous, different authentication state without any warning.
Technical Description
The vulnerability exists in the connection matching logic in lib/url.c. Libcurl maintains a pool of connections and attempts to reuse them to improve performance. To ensure security, it must verify that the new request's security requirements match the properties of the cached connection.
- SASL Mechanism Bypass (IMAP, SMTP, POP3, LDAP)
In SASL-enabled protocols, users can specify a required authentication mechanism via the URL (e.g.,
imap://user:pass;AUTH=GSSAPI@host/) or theCURLOPT_LOGIN_OPTIONSsetting. This string is stored in the connection'soptionsfield.
However, the primary authentication matcher, url_match_auth(), completely ignores the options field. It only compares the user, passwd, sasl_authzid, and oauth_bearer.
Vulnerable Code (lib/url.c:1023):
static bool url_match_auth(struct connectdata *conn, struct url_conn_match *m) {
if(!(m->needle->scheme->flags & PROTOPT_CREDSPERREQUEST)) {
if(Curl_timestrcmp(m->needle->user, conn->user) ||
Curl_timestrcmp(m->needle->passwd, conn->passwd) ||
Curl_timestrcmp(m->needle->sasl_authzid, conn->sasl_authzid) ||
Curl_timestrcmp(m->needle->oauth_bearer, conn->oauth_bearer)) {
return FALSE;
}
// ERROR: conn->options (the AUTH mechanism string) is NEVER compared!
}
return TRUE;
}
- SSH Authentication Type Bypass (SFTP, SCP)
Similarly, for SSH protocols, the user can restrict allowed authentication methods via
CURLOPT_SSH_AUTH_TYPES(e.g., forcing Public Key only and forbidding Passwords). The SSH matching functionssh_config_matches()verifies host keys but fails to verify the handle's authentication policy.
Vulnerable Code (lib/url.c:705):
static bool ssh_config_matches(struct Curl_easy *data, ...) {
// ... host key checks ...
// ERROR: data->set.ssh_auth_types (the security constraint bitmask) is NEVER checked!
return TRUE;
}
Steps to Reproduce
This example uses the IMAP protocol, but the impact is identical across SMTP, POP3, SFTP, and SCP.
- Step 1: Initialize a shared connection pool (
CURLSH). - Step 2 (The Poison Request): Perform a transfer to an IMAP server using a weak authentication mechanism:
imap://privileged_user:secret;[email protected]/The connection is established, authenticated via PLAIN, and added to the pool. - Step 3 (The Secure Request): Another part of the application (or a different tenant in a shared service) performs a transfer requiring a high-security mechanism:
imap://privileged_user:secret;[email protected]/(The developer intends for this to only proceed if Kerberos/GSSAPI is used). - Step 4 (The Bypass): libcurl's matching logic sees that the
userandpassare the same. It ignores the requestedAUTH=GSSAPIconstraint and reuses the existing PLAIN connection.
Result: Transfer 2 succeeds over a session established with a different security policy than requested. No GSSAPI authentication is performed.
Impact
-
Security Policy Bypass Developers use
AUTH=mechanismandSSH_AUTH_TYPESas explicit security controls. If a developer disables a weak authentication method to meet compliance or security requirements, libcurl silently violates that constraint by reusing connections that utilized the forbidden method. -
Confidentiality & Authentication Strength Downgrade In multi-tenant environments (proxies, shared backends), one tenant can "prime" the connection pool with a weak authentication state, which is then inherited by a high-security handle belonging to another tenant. This allows for lateral movement and elevation of authentication state without the required cryptographic proofs (e.g. Kerberos tickets).
-
Identity Leakage Because the authentication state is tied to the connection, reusing a connection established with one set of options for a handle requesting another leads to a breach of isolation between independent security contexts.
Recommended Mitigation
- Update url_match_auth: Add a mandatory string comparison for the
optionsfield.if(Curl_timestrcmp(m->needle->options, conn->options)) return FALSE; - Update ssh_config_matches: Ensure the pooled connection's established authentication method is compatible with the new handle's
ssh_auth_typesbitmask.
Supporting Evidence
- Source Proof: lib/url.c:1023 and lib/url.c:705
- Impact Protocol Audit: IMAP, SMTP, POP3, LDAP, SFTP, SCP all share this vulnerability.