HexBrain

curl · Report #3646072

Negotiate connection reuse with wrong credentials when using CURLAUTH_ANY

Duplicatestatus
mediumseverity
45upvotes
29 Apr 2026disclosed

How it was found

Summary:

CVE-2026-1965 fixed connection reuse for Negotiate authentication by adding url_match_auth_nego() in url_match_conn() at line 1244 of lib/url.c. When a first handle authenticates via Negotiate (Kerberos) on a connection and that connection returns to the pool, a second handle with different credentials should not reuse it.

When the second handle uses CURLAUTH_NEGOTIATE with different credentials, here is what happens:

url_match_auth_ntlm() at line 1239 returns TRUE (because want_ntlm_http is FALSE), so url_match_conn() does not stop and continues. It reaches url_match_auth_nego() at line 1244. This function compares the credentials at lines 1152-1153, finds they are different, and returns FALSE at line 1154. Back in url_match_conn(), this FALSE causes return FALSE to execute at line 1245. The connection is not saved in m->found. The fix works.

However, when the second handle uses CURLAUTH_ANY (which includes both the NTLM and Negotiate bits ), want_ntlm_http is TRUE. url_match_auth_ntlm() enters its credential-mismatch path at line 1086. It checks conn->http_ntlm_state == NTLMSTATE_NONE at line 1091. On a connection authenticated via Negotiate, this condition is true because NTLM was never used. The function saves the connection in m->found = conn at line 1092, then returns FALSE at line 1093. Back in url_match_conn(), this FALSE causes return FALSE to execute at line 1240. The function url_match_conn() terminates here. url_match_auth_nego() at line 1244 is never called.

After the pool iteration, url_match_result() at line 1267 only tests whether match->found is non-NULL. It is (saved at line 1092). Curl_attach_connection() is called at line 1270. The second handle is attached to the first handle's connection. On this connection, the Negotiate handshake is already completed (GSS_AUTHSUCC). Curl does not generate a new Authorization header (http_negotiate.c:254 sets authp->done = TRUE). The request is sent on a connection already authenticated under the first handle's identity.

The root cause is line 1092: m->found = conn is set when http_ntlm_state == NTLMSTATE_NONE, without checking http_negotiate_state.

Affected version:

The vulnerability was identified by source code analysis of curl 8.20.0-DEV (master branch).

Impact

Same impact as CVE-2026-1965

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