curl · Report #3973190
CVE-2026-86411: FTP connection reuse inherits client-certificate
How it was found
Summary
An ftp:// transfer configured with CURLUSESSL_NONE can reuse a pooled FTP control connection that a previous easy handle upgraded with STARTTLS and authenticated using a client certificate. The second handle performs neither a new TLS handshake nor a new FTP login, so the server continues to authorize it under the first handle's certificate identity.
This is a regression introduced in commit 4ff212f8ed328fb95261e11add8f4d2f0616895a ("url: connection reuse fixes for starttls"). It is closely related to CVE-2016-5420 (client-certificate identity reuse across connections).
Root cause
Three things combine to allow this:
-
FTP declares
PROTOPT_SSL_REUSE(lib/protocol.c), sourl_match_ssl_use()(lib/url.c:712-730) accepts an existing TLS-upgraded connection for a later plainftp://transfer. -
For
CURLUSESSL_NONE, connection matching setsmay_tls = falseandrequire_tls = false(lib/url.c:1187-1188).url_match_ssl_config()(lib/url.c:883-895) only callsCurl_ssl_conn_config_match()whenPROTOPT_SSLis set ormay_tlsis true. Neither condition holds, so the client-certificate configuration is never compared. -
Commit
4ff212f8edchangedCurl_ftp_conns_match()(lib/ftp.c:4472-4492) from exactuse_sslequality (!=) to rejecting only when the new value is greater than the pooled connection's value (>). This permits theCURLUSESSL_CONTROL->CURLUSESSL_NONEdirection.
Impact
A handle configured with no client certificate silently inherits the TLS session and certificate identity of a previous handle that used the same connection pool, same FTP destination, and same FTP credentials. The second handle can then perform operations that the server authorizes based on the first handle's certificate.
Prerequisites:
- Two handles share a connection pool and target the same FTP server with the same
USER/PASS. - The first handle uses
CURLUSESSL_CONTROLwith a privileged client certificate. - The second handle uses
CURLUSESSL_NONEwith no client certificate. - The FTP server derives authorization from the TLS client certificate.
I consider this Low severity given the narrow prerequisites, but the result is a cross-handle authentication bypass, not merely stronger-than-requested encryption.
Affected versions
curl 8.21.0, plus affected 8.22.0 prerelease/development versions. Introduced by 4ff212f8ed.
Reproduction
- Build curl 8.21.0 or another affected revision with FTP, explicit TLS, and client-certificate support.
- Create a test CA, an FTP server certificate, a privileged client certificate, and a separate unprivileged client certificate.
- Start an FTP server that supports
AUTH TLS, requests client certificates, and records a stable identifier and client-certificate identity for each control connection. - Configure one FTP resource or command to succeed only when the control connection presents the privileged client certificate.
- Use the same ordinary FTP username and password for both privileged and unprivileged test transfers so that the authorization difference comes only from the TLS client identity.
- Create one libcurl multi handle that will provide a shared connection pool.
- Create a first easy handle for the protected FTP resource, set
CURLOPT_USE_SSLtoCURLUSESSL_CONTROL, configure the privileged certificate and key, and add it to the multi handle. - Perform the first transfer and confirm that it succeeds, the server records the privileged certificate identity, and curl leaves the FTP control connection available for reuse.
- Remove the first easy handle while retaining the multi handle and its connection pool.
- Create a second easy handle for the same FTP destination using the same FTP username and password, but set
CURLOPT_USE_SSLtoCURLUSESSL_NONEand configure no client certificate. - Perform the second transfer and record
CURLINFO_NUM_CONNECTS, the FTP response, the underlying server connection identifier, and the certificate identity associated with the request. - Observe the vulnerable result: the second transfer reuses the first TLS-upgraded control connection, opens no new control connection, and accesses the protected resource under the privileged certificate identity.
- Repeat the second transfer with
CURLOPT_FRESH_CONNECTenabled. - Confirm that a new control connection is created without a client certificate and the server denies access.
- Repeat using explicit TLS and the unprivileged certificate on the second handle.
- Confirm that curl creates a connection with the unprivileged identity and the server denies access.
- As a positive control, repeat with the same privileged certificate on both handles and confirm that reuse and authorization are expected.
- Confirm a fix by requiring client-identity configuration compatibility whenever the pooled connection already uses TLS, even when the new transfer itself specifies
CURLUSESSL_NONE. - Repeat the original privileged-then-no-certificate sequence and verify that the second handle does not inherit the first handle's authenticated FTP control connection.
Expected result
A transfer without a client certificate must not reuse a control connection authenticated with another handle's client certificate. It must establish its own connection and receive only its own authorization.
Vulnerable result
Curl permits a weaker FTP configuration to reuse the existing TLS control connection without comparing client-certificate settings. The later handle inherits the earlier handle's privileged certificate identity and authenticated FTP session.
Suggested fix
When an existing connection has TLS (via STARTTLS), compare client-certificate configuration even when the new handle does not itself request TLS (may_tls = false). At minimum, url_match_ssl_config() should also gate on whether the pooled connection already has TLS, not only on whether the new handle wants TLS.
Impact
Summary:
A lower-privileged transfer sharing curl’s connection pool can operate under a previous handle’s authenticated client-certificate identity. If the FTP server grants additional permissions based on that certificate, the later transfer may read, upload, modify, or delete resources it could not access using its own configuration, creating a cross-handle authorization bypass.