Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions SPECS/curl/CVE-2026-1965.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
From 441e8ee4df3e576bf23c30eb31b9fef8c55f5663 Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Thu, 12 Mar 2026 11:59:23 +0000
Subject: [PATCH] url: fix reuse of connections using HTTP Negotiate;
Follow-up: fix copy+paste mistake in url_match_auth_nego

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport of https://github.com/curl/curl/commit/34fa034d9a390c4bd65e2d05262755ec8646ac12.patch https://github.com/curl/curl/commit/f1a39f221d57354990e3eeeddc3404aede2aff70.patch
---
lib/url.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 85 insertions(+), 5 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 436edd8..d62eefa 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -853,6 +853,8 @@ struct url_conn_match {
BIT(may_multiplex);
BIT(want_ntlm_http);
BIT(want_proxy_ntlm_http);
+ BIT(want_nego_http);
+ BIT(want_proxy_nego_http);

BIT(wait_pipe);
BIT(force_reuse);
@@ -861,6 +863,64 @@ struct url_conn_match {
BIT(seen_multiplex_conn);
};

+#if defined(USE_SPNEGO)
+static bool url_match_auth_nego(struct connectdata *conn,
+ struct url_conn_match *m)
+{
+ /* If we are looking for an HTTP+Negotiate connection, check if this is
+ already authenticating with the right credentials. If not, keep looking
+ so that we can reuse Negotiate connections if possible. */
+ if(m->want_nego_http) {
+ if(Curl_timestrcmp(m->needle->user, conn->user) ||
+ Curl_timestrcmp(m->needle->passwd, conn->passwd))
+ return FALSE;
+ }
+ else if(conn->http_negotiate_state != GSS_AUTHNONE) {
+ /* Connection is using Negotiate auth but we do not want Negotiate */
+ return FALSE;
+ }
+
+#ifndef CURL_DISABLE_PROXY
+ /* Same for Proxy Negotiate authentication */
+ if(m->want_proxy_nego_http) {
+ /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
+ * NULL */
+ if(!conn->http_proxy.user || !conn->http_proxy.passwd)
+ return FALSE;
+
+ if(Curl_timestrcmp(m->needle->http_proxy.user,
+ conn->http_proxy.user) ||
+ Curl_timestrcmp(m->needle->http_proxy.passwd,
+ conn->http_proxy.passwd))
+ return FALSE;
+ }
+ else if(conn->proxy_negotiate_state != GSS_AUTHNONE) {
+ /* Proxy connection is using Negotiate auth but we do not want Negotiate */
+ return FALSE;
+ }
+#endif
+ if(m->want_nego_http || m->want_proxy_nego_http) {
+ /* Credentials are already checked, we may use this connection. We MUST
+ * use a connection where it has already been fully negotiated. If it has
+ * not, we keep on looking for a better one. */
+ m->found = conn;
+ if((m->want_nego_http &&
+ (conn->http_negotiate_state != GSS_AUTHNONE)) ||
+ (m->want_proxy_nego_http &&
+ (conn->proxy_negotiate_state != GSS_AUTHNONE))) {
+ /* We must use this connection, no other */
+ m->force_reuse = TRUE;
+ return TRUE;
+ }
+ return FALSE; /* get another */
+ }
+ return TRUE;
+}
+#else
+#define url_match_auth_nego(c, m) ((void)c, (void)m, TRUE)
+#endif
+
+
static bool url_match_conn(struct connectdata *conn, void *userdata)
{
struct url_conn_match *match = userdata;
@@ -1156,6 +1216,13 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
* If it has not, we keep on looking for a better one. */
match->found = conn;

+
+ if(!url_match_auth_nego(conn, match))
+ return FALSE;
+ else if(match->force_reuse)
+ return TRUE;
+
+
if((match->want_ntlm_http &&
(conn->http_ntlm_state != NTLMSTATE_NONE)) ||
(match->want_proxy_ntlm_http &&
@@ -1251,13 +1318,26 @@ ConnectionExists(struct Curl_easy *data,
match.may_multiplex = xfer_may_multiplex(data, needle);

#ifdef USE_NTLM
- match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) &&
- (needle->handler->protocol & PROTO_FAMILY_HTTP));
+ match.want_ntlm_http =
+ (data->state.authhost.want & CURLAUTH_NTLM) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP);
#ifndef CURL_DISABLE_PROXY
match.want_proxy_ntlm_http =
- (needle->bits.proxy_user_passwd &&
- (data->state.authproxy.want & CURLAUTH_NTLM) &&
- (needle->handler->protocol & PROTO_FAMILY_HTTP));
+ needle->bits.proxy_user_passwd &&
+ (data->state.authproxy.want & CURLAUTH_NTLM) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP);
+#endif
+#endif
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+ match.want_nego_http =
+ (data->state.authhost.want & CURLAUTH_NEGOTIATE) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP);
+#ifndef CURL_DISABLE_PROXY
+ match.want_proxy_nego_http =
+ needle->bits.proxy_user_passwd &&
+ (data->state.authproxy.want & CURLAUTH_NEGOTIATE) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP);
#endif
#endif

--
2.45.4

149 changes: 149 additions & 0 deletions SPECS/curl/CVE-2026-3783.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
From e3d7401a32a46516c9e5ee877e613e62ed35bddc Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Fri, 6 Mar 2026 23:13:07 +0100
Subject: [PATCH] http: only send bearer if auth is allowed

Verify with test 2006

Closes #20843

Upstream Patch reference: https://github.com/curl/curl/commit/e3d7401a32a46516c9e5ee877e613e62ed35bddc.patch
---
lib/http.c | 1 +
tests/data/Makefile.am | 2 +-
tests/data/test2006 | 98 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 100 insertions(+), 1 deletion(-)
create mode 100644 tests/data/test2006

diff --git a/lib/http.c b/lib/http.c
index 35e7085..4de1667 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -650,6 +650,7 @@ output_auth_headers(struct Curl_easy *data,
if(authstatus->picked == CURLAUTH_BEARER) {
/* Bearer */
if((!proxy && data->set.str[STRING_BEARER] &&
+ Curl_auth_allowed_to_host(data) &&
!Curl_checkheaders(data, STRCONST("Authorization")))) {
auth = "Bearer";
result = http_output_bearer(data);
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 776b593..26e015f 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -238,7 +238,7 @@ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \
test1955 test1956 test1957 test1958 test1959 test1960 test1964 \
test1970 test1971 test1972 test1973 test1974 test1975 test1976 \
\
-test2000 test2001 test2002 test2003 test2004 \
+test2000 test2001 test2002 test2003 test2004 test2006 \
\
test2023 \
test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \
diff --git a/tests/data/test2006 b/tests/data/test2006
new file mode 100644
index 0000000..4b8b269
--- /dev/null
+++ b/tests/data/test2006
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+netrc
+HTTP
+</keywords>
+</info>
+# Server-side
+<reply>
+<data crlf="yes">
+HTTP/1.1 301 Follow this you fool
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Location: http://b.com/%TESTNUMBER0002
+
+-foo-
+</data>
+
+<data2 crlf="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 7
+Connection: close
+
+target
+</data2>
+
+<datacheck crlf="yes">
+HTTP/1.1 301 Follow this you fool
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Location: http://b.com/%TESTNUMBER0002
+
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 7
+Connection: close
+
+target
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+proxy
+</features>
+<name>
+.netrc default with redirect plus oauth2-bearer
+</name>
+<command>
+--netrc --netrc-file %LOGDIR/netrc%TESTNUMBER --oauth2-bearer SECRET_TOKEN -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/
+</command>
+<file name="%LOGDIR/netrc%TESTNUMBER" >
+default login testuser password testpass
+</file>
+</client>
+
+<verify>
+<protocol crlf="yes">
+GET http://a.com/ HTTP/1.1
+Host: a.com
+Authorization: Bearer SECRET_TOKEN
+User-Agent: curl/%VERSION
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+GET http://b.com/%TESTNUMBER0002 HTTP/1.1
+Host: b.com
+User-Agent: curl/%VERSION
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+</protocol>
+</verify>
+</testcase>
--
2.43.0

Loading
Loading