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
50 changes: 50 additions & 0 deletions SPECS/curl/CVE-2026-4873.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
From 27418ff376aa27a2b57aa2c1cd2bdd0397836116 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 24 Mar 2026 08:35:08 +0100
Subject: [PATCH] url: do not reuse a non-tls starttls connection if new
requires TLS

Reported-by: Arkadi Vainbrand

Closes #21082

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/curl/curl/commit/507e7be573b0a76fca597b75ff7cb27a66e7d865.patch
---
lib/url.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/url.c b/lib/url.c
index 88f559a..2ba5311 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -841,7 +841,7 @@ struct url_conn_match {
BIT(want_proxy_ntlm_http);
BIT(want_nego_http);
BIT(want_proxy_nego_http);
-
+ BIT(req_tls); /* require TLS use from a clear-text start */
BIT(wait_pipe);
BIT(force_reuse);
BIT(seen_pending_conn);
@@ -900,6 +900,9 @@ static bool url_match_auth_nego(struct connectdata *conn,
}
return FALSE; /* get another */
}
+ else if(m->req_tls)
+ /* a clear-text STARTTLS protocol with required TLS */
+ return FALSE;
return TRUE;
}
#else
@@ -1326,6 +1329,7 @@ ConnectionExists(struct Curl_easy *data,
(needle->handler->protocol & PROTO_FAMILY_HTTP);
#endif
#endif
+ match.req_tls = data->set.use_ssl >= CURLUSESSL_CONTROL;

/* Find a connection in the pool that matches what "data + needle"
* requires. If a suitable candidate is found, it is attached to "data". */
--
2.45.4

325 changes: 325 additions & 0 deletions SPECS/curl/CVE-2026-6276.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
From 3a19987a87f393d9394fe5acc7643f6c263c92db Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 14 Apr 2026 08:51:44 +0200
Subject: [PATCH] urldata: move cookiehost to struct SingleRequest

To make it scoped for the single request appropriately.

Reported-by: Muhamad Arga Reksapati

Verify with libtest 2504: a custom Host *disabled* on reused handle

Closes #21312

Upstream Patch Reference: https://github.com/curl/curl/commit/3a19987a87f393d9394fe5acc7643f6c263c92db
---
lib/http.c | 14 +++---
lib/request.c | 3 ++
lib/request.h | 3 ++
lib/url.c | 2 +-
lib/urldata.h | 3 --
tests/data/Makefile.am | 2 +-
tests/data/test2504 | 52 +++++++++++++++++++++
tests/libtest/Makefile.inc | 5 +-
tests/libtest/lib2504.c | 93 ++++++++++++++++++++++++++++++++++++++
9 files changed, 165 insertions(+), 12 deletions(-)
create mode 100644 tests/data/test2504
create mode 100644 tests/libtest/lib2504.c

diff --git a/lib/http.c b/lib/http.c
index 4de1667..7d328e0 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1543,6 +1543,9 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
data->state.first_remote_protocol = conn->handler->protocol;
}
Curl_safefree(aptr->host);
+#ifndef CURL_DISABLE_COOKIES
+ Curl_safefree(data->req.cookiehost);
+#endif

ptr = Curl_checkheaders(data, STRCONST("Host"));
if(ptr && (!data->state.this_is_a_follow ||
@@ -1577,8 +1580,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
if(colon)
*colon = 0; /* The host must not include an embedded port number */
}
- Curl_safefree(aptr->cookiehost);
- aptr->cookiehost = cookiehost;
+ data->req.cookiehost = cookiehost;
}
#endif

@@ -2097,8 +2099,8 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
int rc = 1;

if(data->cookies && data->state.cookie_engine) {
- const char *host = data->state.aptr.cookiehost ?
- data->state.aptr.cookiehost : conn->host.name;
+ const char *host = data->req.cookiehost ?
+ data->req.cookiehost : conn->host.name;
const bool secure_context =
conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
strcasecompare("localhost", host) ||
@@ -2920,8 +2922,8 @@ CURLcode Curl_http_header(struct Curl_easy *data,
if(v) {
/* If there is a custom-set Host: name, use it here, or else use
* real peer hostname. */
- const char *host = data->state.aptr.cookiehost ?
- data->state.aptr.cookiehost : conn->host.name;
+ const char *host = data->req.cookiehost ?
+ data->req.cookiehost : conn->host.name;
const bool secure_context =
conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
strcasecompare("localhost", host) ||
diff --git a/lib/request.c b/lib/request.c
index 310e4ea..088425d 100644
--- a/lib/request.c
+++ b/lib/request.c
@@ -124,6 +124,9 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)

#ifndef CURL_DISABLE_DOH
Curl_doh_close(data);
+#endif
+#ifndef CURL_DISABLE_COOKIES
+ Curl_safefree(req->cookiehost);
#endif
/* Can no longer memset() this struct as we need to keep some state */
req->size = -1;
diff --git a/lib/request.h b/lib/request.h
index bb72247..90cb0ae 100644
--- a/lib/request.h
+++ b/lib/request.h
@@ -119,6 +119,9 @@ struct SingleRequest {
#ifndef CURL_DISABLE_DOH
struct doh_probes *doh; /* DoH specific data for this request */
#endif
+#ifndef CURL_DISABLE_COOKIES
+ char *cookiehost;
+#endif
#ifndef CURL_DISABLE_COOKIES
unsigned char setcookies;
#endif
diff --git a/lib/url.c b/lib/url.c
index 2ba5311..6ea7b30 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -317,7 +317,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.aptr.ref);
Curl_safefree(data->state.aptr.host);
#ifndef CURL_DISABLE_COOKIES
- Curl_safefree(data->state.aptr.cookiehost);
+ Curl_safefree(data->req.cookiehost);
#endif
#ifndef CURL_DISABLE_RTSP
Curl_safefree(data->state.aptr.rtsp_transport);
diff --git a/lib/urldata.h b/lib/urldata.h
index 704fb7a..026fa2a 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1331,9 +1331,6 @@ struct UrlState {
char *rangeline;
char *ref;
char *host;
-#ifndef CURL_DISABLE_COOKIES
- char *cookiehost;
-#endif
#ifndef CURL_DISABLE_RTSP
char *rtsp_transport;
#endif
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 26e015f..b0d1b0a 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -259,7 +259,7 @@ test2308 test2309 \
\
test2400 test2401 test2402 test2403 test2404 test2405 test2406 \
\
-test2500 test2501 test2502 test2503 \
+test2500 test2501 test2502 test2503 test2504 \
\
test2600 test2601 test2602 test2603 test2604 \
\
diff --git a/tests/data/test2504 b/tests/data/test2504
new file mode 100644
index 0000000..8cec1c8
--- /dev/null
+++ b/tests/data/test2504
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+cookies
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data crlf="headers" nocheck="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: server.example.com
+Content-Length: 47
+Set-Cookie: sid=SECRET123; Path=/
+
+file contents should appear once for each file
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<tool>
+lib%TESTNUMBER
+</tool>
+<name>
+custom Host with cookie, handle reuse, no custom Host:
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="headers">
+GET / HTTP/1.1
+Host: victim.internal
+Accept: */*
+
+GET / HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
index 8f58fd6..b393665 100644
--- a/tests/libtest/Makefile.inc
+++ b/tests/libtest/Makefile.inc
@@ -79,7 +79,7 @@ LIBTESTPROGS = libauthretry libntlmconnect libprereq \
lib1970 lib1971 lib1972 lib1973 lib1974 lib1975 \
lib2301 lib2302 lib2304 lib2305 lib2306 lib2308 lib2309 \
lib2402 lib2404 lib2405 \
- lib2502 \
+ lib2502 lib2504 \
lib3010 lib3025 lib3026 lib3027 \
lib3100 lib3101 lib3102 lib3103 lib3207

@@ -698,6 +698,9 @@ lib2405_LDADD = $(TESTUTIL_LIBS)
lib2502_SOURCES = lib2502.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(WARNLESS)
lib2502_LDADD = $(TESTUTIL_LIBS)

+lib2504_SOURCES = lib2504.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE)
+lib2504_LDADD = $(TESTUTIL_LIBS)
+
lib3010_SOURCES = lib3010.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib3010_LDADD = $(TESTUTIL_LIBS)

diff --git a/tests/libtest/lib2504.c b/tests/libtest/lib2504.c
new file mode 100644
index 0000000..72b965d
--- /dev/null
+++ b/tests/libtest/lib2504.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Linus Nielsen Feltzing <linus@haxx.se>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "first.h"
+
+#include "testtrace.h"
+
+static size_t sink2504(char *ptr, size_t size, size_t nmemb, void *ud)
+{
+ (void)ptr;
+ (void)ud;
+ return size * nmemb;
+}
+
+static void dump_cookies2504(CURL *h, const char *tag)
+{
+ struct curl_slist *cookies = NULL;
+ struct curl_slist *nc;
+ CURLcode rc = curl_easy_getinfo(h, CURLINFO_COOKIELIST, &cookies);
+
+ curl_mprintf("== %s ==\n", tag);
+ if(rc) {
+ curl_mprintf("getinfo error: %d\n", (int)rc);
+ return;
+ }
+ for(nc = cookies; nc; nc = nc->next)
+ puts(nc->data);
+ curl_slist_free_all(cookies);
+}
+
+static CURLcode test_lib2504(const char *URL)
+{
+ CURL *curl;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
+ struct curl_slist *hdrs = NULL;
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ curl_mfprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ curl = curl_easy_init();
+ if(!curl) {
+ curl_mfprintf(stderr, "curl_easy_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ hdrs = curl_slist_append(hdrs, "Host: victim.internal");
+ if(hdrs) {
+ test_setopt(curl, CURLOPT_WRITEFUNCTION, sink2504);
+ test_setopt(curl, CURLOPT_COOKIEFILE, "");
+ test_setopt(curl, CURLOPT_HTTPHEADER, hdrs);
+ test_setopt(curl, CURLOPT_URL, URL);
+
+ result = curl_easy_perform(curl);
+ curl_mprintf("req1=%d\n", (int)result);
+ dump_cookies2504(curl, "after request 1");
+
+ test_setopt(curl, CURLOPT_HTTPHEADER, NULL);
+ test_setopt(curl, CURLOPT_URL, URL);
+
+ result = curl_easy_perform(curl);
+ curl_mprintf("req2=%d\n", (int)result);
+ dump_cookies2504(curl, "after request 2");
+ }
+test_cleanup:
+ curl_slist_free_all(hdrs);
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+
+ return result;
+}
--
2.45.4

Loading
Loading