From b0626fff8538e3dd4a52f148d91c8348d51d64d1 Mon Sep 17 00:00:00 2001
From: Carlos Garcia Campos <cgarcia@igalia.com>
Date: Fri, 27 Feb 2026 12:03:25 +0100
Subject: [PATCH] cookies: do not send cookies to a HTTP proxy for a HTTPS
 request

Closes #502

CVE: CVE-2026-5119
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/b0626fff8538e3dd4a52f148d91c8348d51d64d1]
Signed-off-by: Peter Marko <peter.marko@siemens.com>

---
 libsoup/cookies/soup-cookie-jar.c | 24 +++++++++++-----
 tests/proxy-test.c                | 47 +++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/libsoup/cookies/soup-cookie-jar.c b/libsoup/cookies/soup-cookie-jar.c
index 7e200f8f..6a996ffe 100644
--- a/libsoup/cookies/soup-cookie-jar.c
+++ b/libsoup/cookies/soup-cookie-jar.c
@@ -885,18 +885,28 @@ process_set_cookie_header (SoupMessage *msg, gpointer user_data)
 	g_slist_free (new_cookies);
 }
 
+static gboolean
+allow_cookies_for_request (SoupMessage *msg)
+{
+        /* Do not send cookies to a HTTP proxy for a HTTPS request */
+        return soup_message_get_method (msg) != SOUP_METHOD_CONNECT || !soup_connection_is_tunnelled (soup_message_get_connection (msg));
+}
+
 static void
 msg_starting_cb (SoupMessage *msg, gpointer feature)
 {
 	SoupCookieJar *jar = SOUP_COOKIE_JAR (feature);
-	GSList *cookies;
+	GSList *cookies = NULL;
+
+        if (allow_cookies_for_request (msg)) {
+                cookies = soup_cookie_jar_get_cookie_list_with_same_site_info (jar, soup_message_get_uri (msg),
+                                                                               soup_message_get_first_party (msg),
+                                                                               soup_message_get_site_for_cookies (msg),
+                                                                               TRUE,
+                                                                               SOUP_METHOD_IS_SAFE (soup_message_get_method (msg)),
+                                                                               soup_message_get_is_top_level_navigation (msg));
+        }
 
-	cookies = soup_cookie_jar_get_cookie_list_with_same_site_info (jar, soup_message_get_uri (msg),
-	                                                               soup_message_get_first_party (msg),
-							               soup_message_get_site_for_cookies (msg),
-								       TRUE,
-							               SOUP_METHOD_IS_SAFE (soup_message_get_method (msg)),
-							               soup_message_get_is_top_level_navigation (msg));
 	if (cookies != NULL) {
 		char *cookie_header = soup_cookies_to_cookie_header (cookies);
 		soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_COOKIE, cookie_header, SOUP_HEADER_VALUE_TRUSTED);
diff --git a/tests/proxy-test.c b/tests/proxy-test.c
index 68c97aca..945de2cc 100644
--- a/tests/proxy-test.c
+++ b/tests/proxy-test.c
@@ -406,6 +406,52 @@ do_proxy_connect_error_test (gconstpointer data)
         soup_test_session_abort_unref (session);
 }
 
+static void
+connect_message_wrote_headers_cb (SoupMessage *msg, guint *counter)
+{
+        SoupMessageHeaders *hdrs;
+
+        *counter += 1;
+
+        hdrs = soup_message_get_request_headers (msg);
+        if (soup_message_get_method (msg) == SOUP_METHOD_CONNECT)
+                g_assert_null (soup_message_headers_get_one (hdrs, "Cookie"));
+        else
+                g_assert_nonnull (soup_message_headers_get_one (hdrs, "Cookie"));
+}
+
+static void
+request_queued_cb (SoupSession *session, SoupMessage *msg, guint *counter)
+{
+        g_signal_connect (msg, "wrote-headers", G_CALLBACK (connect_message_wrote_headers_cb), counter);
+}
+
+static void
+do_proxy_secure_cookies_test (void)
+{
+        SoupSession *session;
+        SoupMessage *msg;
+        SoupCookieJar *jar;
+        guint counter = 0;
+
+        SOUP_TEST_SKIP_IF_NO_APACHE;
+        SOUP_TEST_SKIP_IF_NO_TLS;
+
+        session = soup_test_session_new ("proxy-resolver", proxy_resolvers[SIMPLE_PROXY], NULL);
+        g_signal_connect (session, "request-queued", G_CALLBACK (request_queued_cb), &counter);
+
+        soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
+        jar = SOUP_COOKIE_JAR (soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR));
+
+        msg = soup_message_new (SOUP_METHOD_GET, HTTPS_SERVER);
+        soup_cookie_jar_set_cookie (jar, soup_message_get_uri (msg), "user=password; secure");
+        soup_test_session_send_message (session, msg);
+        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
+        g_assert_cmpuint (counter, ==, 2);
+
+        soup_test_session_abort_unref (session);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -438,6 +484,7 @@ main (int argc, char **argv)
         g_test_add_func ("/proxy/auth-redirect", do_proxy_auth_redirect_test);
 	g_test_add_func ("/proxy/auth-cache", do_proxy_auth_cache_test);
         g_test_add_data_func ("/proxy/connect-error", base_https_uri, do_proxy_connect_error_test);
+        g_test_add_func ("/proxy/secure-cookies", do_proxy_secure_cookies_test);
 
 	ret = g_test_run ();
 
