Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libsoup2 for openSUSE:Factory 
checked in at 2026-10-14 18:34:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libsoup2 (Old)
 and      /work/SRC/openSUSE:Factory/.libsoup2.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libsoup2"

Wed Oct 14 18:34:06 2026 rev:29 rq:1384566 version:2.74.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/libsoup2/libsoup2.changes        2026-10-08 
15:12:54.985568735 +0200
+++ /work/SRC/openSUSE:Factory/.libsoup2.new.3698736/libsoup2.changes   
2026-10-14 18:34:26.606154404 +0200
@@ -1,0 +2,14 @@
+Mon Oct 12 19:09:21 UTC 2026 - Michael Gorse <[email protected]>
+
+- CVE-2026-103399: incomplete request body draining in HTTP/1.x
+  early responses can allow HTTP request smuggling (bsc#1283831)
+  * libsoup2-CVE-2026-103399.patch
+
+-------------------------------------------------------------------
+Thu Oct  8 16:15:20 UTC 2026 - Michael Gorse <[email protected]>
+
+- CVE-2026-15713: SoupCache: libsoup: HTTP/2 frame window
+  exhaustion remote denial of service via memory leak (bsc#1271448)
+  * libsoup2-CVE-2026-15713.patch
+
+-------------------------------------------------------------------

New:
----
  libsoup2-CVE-2026-103399.patch
  libsoup2-CVE-2026-15713.patch

----------(New B)----------
  New:  early responses can allow HTTP request smuggling (bsc#1283831)
  * libsoup2-CVE-2026-103399.patch
  New:  exhaustion remote denial of service via memory leak (bsc#1271448)
  * libsoup2-CVE-2026-15713.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libsoup2.spec ++++++
--- /var/tmp/diff_new_pack.JjBNbJ/_old  2026-10-14 18:34:28.309226519 +0200
+++ /var/tmp/diff_new_pack.JjBNbJ/_new  2026-10-14 18:34:28.311226604 +0200
@@ -128,6 +128,10 @@
 Patch50:        libsoup2-CVE-2026-102560.patch
 # PATCH-FIX-UPSTREAM libsoup2-CVE-2026-102557.patch bsc#1283301 bsc#1283303 
[email protected] -- websocket: Cap message reassembly and outgoing frames at the 
buffer limit.
 Patch51:        libsoup2-CVE-2026-102557.patch
+# PATCH-FIX-UPSTREAM libsoup2-CVE-2026-15713.patch bsc#1271448 [email protected] 
-- cache: Reject caching authenticated responses in shared caches.
+Patch52:        libsoup2-CVE-2026-15713.patch
+# PATCH-FIX-UPSTREAM libsoup2-CVE-2026-103399.patch bsc#1283831 
[email protected] -- server: Close the connection after an early response to 
Expect: 100-continue.
+Patch53:        libsoup2-CVE-2026-103399.patch
 
 BuildRequires:  glib-networking
 BuildRequires:  meson >= 0.50

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.JjBNbJ/_old  2026-10-14 18:34:28.371229145 +0200
+++ /var/tmp/diff_new_pack.JjBNbJ/_new  2026-10-14 18:34:28.375229314 +0200
@@ -1,7 +1,7 @@
-mtime: 1791317579
-commit: a5c48ee5831de2c24c1bb6b38d0f95fdac1261e3f937831a16628a969b3d8149
+mtime: 1791834825
+commit: 3b7bb3e063cd6a5b12ee6854a3ad47139f45b742cdb479111a09dc01a32a8b7d
 url: https://src.opensuse.org/GNOME/libsoup2
-revision: a5c48ee5831de2c24c1bb6b38d0f95fdac1261e3f937831a16628a969b3d8149
+revision: 3b7bb3e063cd6a5b12ee6854a3ad47139f45b742cdb479111a09dc01a32a8b7d
 trackingbranch: factory
 projectscmsync: https://src.opensuse.org/GNOME/_ObsPrj
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-10-12 21:53:45.000000000 +0200
@@ -0,0 +1,4 @@
+*.obscpio
+*.osc
+_build.*
+.pbuild

++++++ libsoup2-CVE-2026-103399.patch ++++++
>From 1b7fee598e0f644008028ca69d1ba74de8bc7db2 Mon Sep 17 00:00:00 2001
From: Patrick Griffis <[email protected]>
Date: Fri, 4 Sep 2026 14:40:03 -0500
Subject: [PATCH] server: Close the connection after an early response to
 Expect: 100-continue

When a client sends "Expect: 100-continue" with a body and the server
produces a final response before reading that body (for example a 401
from a SoupAuthDomain), libsoup marked the read side done without draining
the declared body bytes or closing the connection. RFC 9110 allows the
client to send the body without waiting, so those bytes may already be in
the socket buffer; on a kept-alive connection they were then parsed as the
next request, allowing request smuggling behind a connection-pooling proxy.

Send "Connection: close" in that case so the connection is torn down and
the undrained body is discarded, as RFC 9112 requires.

Fixes #539
---
 .../http1/soup-server-message-io-http1.c      |  13 ++
 tests/server-test.c                           | 116 ++++++++++++++++++
 2 files changed, 129 insertions(+)

Index: libsoup-2.74.3/libsoup/soup-message-io.c
===================================================================
--- libsoup-2.74.3.orig/libsoup/soup-message-io.c
+++ libsoup-2.74.3/libsoup/soup-message-io.c
@@ -411,6 +411,18 @@ io_write (SoupMessage *msg, gboolean blo
                         * server did not set an error.
                         */
                        soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
+                } else if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING &&
+                           !SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
+                        /* The client requested "Expect: 100-continue" but the
+                         * server is sending a final response without reading
+                         * the request body. The client may already have sent
+                         * that body (RFC 9110 permits sending it without
+                         * waiting), and those undrained bytes must not be
+                         * parsed as the next request on a reused connection.
+                         * Force the connection closed, per RFC 9112.
+                         */
+                        soup_message_headers_replace (msg->response_headers,
+                                                             "Connection", 
"close");
                }
 
                if (!io->write_buf->len) {
Index: libsoup-2.74.3/tests/server-test.c
===================================================================
--- libsoup-2.74.3.orig/tests/server-test.c
+++ libsoup-2.74.3/tests/server-test.c
@@ -578,6 +578,122 @@ do_multi_family_test (ServerData *sd, gc
        do_multi_test (sd, uri1, uri2);
 }
 
+static gboolean smuggle_auth_callback_hit;
+
+static void
+smuggle_target_callback (SoupServer        *server,
+                        SoupMessage *msg,
+                        const char        *path,
+                        GHashTable        *query,
+                         SoupClientContext *context,
+                        gpointer           data)
+{
+       /* The smuggled request must never be dispatched */
+       g_assert_not_reached ();
+}
+
+static gboolean
+smuggle_auth_callback (SoupAuthDomain    *domain,
+                      SoupMessage *msg,
+                      const char        *username,
+                      const char        *password,
+                      gpointer           user_data)
+{
+       smuggle_auth_callback_hit = TRUE;
+
+       /* Always reject, so the server sends a 401 before reading the body */
+       return FALSE;
+}
+
+/* A client that requests "Expect: 100-continue" may still send its body
+ * without waiting. If the server produces an early final response (here a 401
+ * from an auth domain) without draining that body, the leftover bytes must not
+ * be parsed as the next request on a kept-alive connection. See issue #539.
+ */
+static void
+do_early_response_expect_continue_test (void)
+{
+       SoupServer *server;
+       SoupAuthDomain *auth_domain;
+       SoupURI *uri;
+       GSocketClient *client;
+       GSocketConnection *conn;
+       GInputStream *istream;
+       GOutputStream *ostream;
+       GError *error = NULL;
+       char *request;
+       const char *smuggled = "GET /smuggled HTTP/1.1\r\nHost: 
localhost\r\n\r\n";
+       char buf[4096];
+       gsize total = 0;
+       gssize n;
+
+       smuggle_auth_callback_hit = FALSE;
+
+       server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
+       soup_server_add_handler (server, "/smuggled", smuggle_target_callback, 
NULL, NULL);
+       auth_domain = soup_auth_domain_basic_new ("realm", "smuggle-test",
+                                                 "auth-callback", 
smuggle_auth_callback,
+                                                 NULL);
+       soup_auth_domain_add_path (auth_domain, "/protected");
+       soup_server_add_auth_domain (server, auth_domain);
+       g_object_unref (auth_domain);
+
+       uri = soup_test_server_get_uri (server, "http", "127.0.0.1");
+
+       client = g_socket_client_new ();
+       conn = g_socket_client_connect_to_host (client, "127.0.0.1", 
soup_uri_get_port (uri), NULL, &error);
+       g_assert_no_error (error);
+       /* Bound the read so the buggy behaviour (connection kept open) fails
+        * quickly rather than hanging.
+        */
+       g_socket_set_timeout (g_socket_connection_get_socket (conn), 5);
+       istream = g_io_stream_get_input_stream (G_IO_STREAM (conn));
+       ostream = g_io_stream_get_output_stream (G_IO_STREAM (conn));
+
+       /* Send credentials so the auth domain reaches smuggle_auth_callback
+        * and rejects there, rather than refusing for lack of a header.
+        */
+       request = g_strdup_printf ("POST /protected HTTP/1.1\r\n"
+                                  "Host: localhost\r\n"
+                                  "Authorization: Basic 
dXNlcjpwYXNzd29yZA==\r\n"
+                                  "Content-Length: %zu\r\n"
+                                  "Expect: 100-continue\r\n"
+                                  "\r\n"
+                                  "%s",
+                                  strlen (smuggled), smuggled);
+       g_output_stream_write_all (ostream, request, strlen (request), NULL, 
NULL, &error);
+       g_assert_no_error (error);
+
+       /* Read until the server closes the connection. A conformant server
+        * sends a single 401 and closes; the smuggled request is never run.
+        */
+       while ((n = g_input_stream_read (istream, buf + total,
+                                        sizeof (buf) - 1 - total, NULL, 
&error)) > 0) {
+               total += n;
+               if (total >= sizeof (buf) - 1)
+                       break;
+       }
+       buf[total] = '\0';
+
+       g_assert_true (smuggle_auth_callback_hit);
+       g_assert_nonnull (strstr (buf, " 401 "));
+       /* The server must not have produced a second response for the
+        * smuggled request.
+        */
+       g_assert_null (strstr (buf, " 200 "));
+       /* The connection must have been closed cleanly (EOF), not left open */
+       g_assert_no_error (error);
+       g_assert_cmpint (n, ==, 0);
+       g_clear_error (&error);
+
+       g_free (request);
+       g_io_stream_close (G_IO_STREAM (conn), NULL, NULL);
+       g_object_unref (conn);
+       g_object_unref (client);
+       soup_uri_free (uri);
+       soup_test_server_quit_unref (server);
+}
+
 static void
 do_gsocket_import_test (void)
 {
@@ -1522,6 +1638,7 @@ main (int argc, char **argv)
                    NULL, do_multi_scheme_test, server_teardown);
        g_test_add ("/server/multi/family", ServerData, NULL,
                    NULL, do_multi_family_test, server_teardown);
+       g_test_add_func ("/server/early-response-expect-continue", 
do_early_response_expect_continue_test);
        g_test_add_func ("/server/import/gsocket", do_gsocket_import_test);
        g_test_add_func ("/server/import/fd", do_fd_import_test);
        g_test_add_func ("/server/accept/iostream", do_iostream_accept_test);

++++++ libsoup2-CVE-2026-15713.patch ++++++
>From 24fb645fa949ece7d7e10363b77cf2d5fa2c2469 Mon Sep 17 00:00:00 2001
From: Milan Crha <[email protected]>
Date: Fri, 4 Sep 2026 10:34:22 +0200
Subject: [PATCH] cache: Reject caching authenticated responses in shared
 caches

RFC 7234 Section 3.2 forbids to save to a shared cache a response to
a request containing an Authorization header unless the response
explicitly allows it with public, must-revalidate or s-maxage.

This is CVE-2026-15713.

Closes https://gitlab.gnome.org/GNOME/libsoup/-/work_items/541
---
 libsoup/cache/soup-cache.c | 15 +++++++++++
 tests/cache-test.c         | 55 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)

Index: libsoup-2.74.3/libsoup/soup-cache.c
===================================================================
--- libsoup-2.74.3.orig/libsoup/soup-cache.c
+++ libsoup-2.74.3/libsoup/soup-cache.c
@@ -155,6 +155,8 @@ get_cacheability (SoupCache *cache, Soup
        SoupCacheability cacheability;
        const char *cache_control, *content_type;
        gboolean has_max_age = FALSE;
+       gboolean permits_authorized_shared_caching = FALSE;
+       SoupCachePrivate *priv = soup_cache_get_instance_private (cache);
 
        /* 1. The request method must be cacheable */
        if (msg->method == SOUP_METHOD_GET)
@@ -183,6 +185,11 @@ get_cacheability (SoupCache *cache, Soup
                                soup_header_free_param_list (hash);
                                return SOUP_CACHE_UNCACHEABLE;
                        }
+
+                       permits_authorized_shared_caching =
+                               g_hash_table_lookup_extended (hash, "public", 
NULL, NULL) ||
+                               g_hash_table_lookup_extended (hash, 
"must-revalidate", NULL, NULL) ||
+                               g_hash_table_lookup_extended (hash, "s-maxage", 
NULL, NULL);
                }
 
                /* 2. The 'no-store' cache directive does not appear in the
@@ -207,6 +214,15 @@ get_cacheability (SoupCache *cache, Soup
                soup_header_free_param_list (hash);
        }
 
+       /* RFC 7234 Section 3.2: a shared cache MUST NOT store a response to
+        * a request containing an Authorization header unless the response
+        * explicitly allows it with public, must-revalidate or s-maxage.
+        */
+       if (priv->cache_type == SOUP_CACHE_SHARED &&
+           !permits_authorized_shared_caching &&
+           soup_message_headers_get_one (msg->request_headers, 
"Authorization"))
+               return SOUP_CACHE_UNCACHEABLE;
+
        /* Section 13.9 */
        if ((soup_message_get_uri (msg))->query &&
            !soup_message_headers_get_one (msg->response_headers, "Expires") &&
Index: libsoup-2.74.3/tests/cache-test.c
===================================================================
--- libsoup-2.74.3.orig/tests/cache-test.c
+++ libsoup-2.74.3/tests/cache-test.c
@@ -88,6 +88,7 @@ server_callback (SoupServer *server, Sou
        if (status == SOUP_STATUS_OK) {
                GChecksum *sum;
                const char *body;
+               const char *authorization;
 
                sum = g_checksum_new (G_CHECKSUM_SHA256);
                g_checksum_update (sum, (guchar *)path, strlen (path));
@@ -95,6 +96,9 @@ server_callback (SoupServer *server, Sou
                        g_checksum_update (sum, (guchar *)last_modified, strlen 
(last_modified));
                if (etag)
                        g_checksum_update (sum, (guchar *)etag, strlen (etag));
+               authorization = soup_message_headers_get_one 
(msg->request_headers, "Authorization");
+               if (authorization)
+                       g_checksum_update (sum, (guchar *)authorization, strlen 
(authorization));
                body = g_checksum_get_string (sum);
                soup_message_set_response (msg, "text/plain",
                                           SOUP_MEMORY_COPY,
@@ -685,6 +689,60 @@ do_headers_test (gconstpointer data)
        g_free (body1);
 }
 
+static void
+do_shared_cache_authorization_test (gconstpointer data)
+{
+       SoupURI *base_uri = (SoupURI *)data;
+       SoupSession *attacker_session;
+       SoupSession *victim_session;
+       SoupCache *attacker_cache;
+       SoupCache *victim_cache;
+       char *cache_dir;
+       char *attacker_body;
+       char *victim_body;
+
+       cache_dir = g_dir_make_tmp ("cache-test-XXXXXX", NULL);
+       debug_printf (2, "  Caching to %s\n", cache_dir);
+
+       attacker_cache = soup_cache_new (cache_dir, SOUP_CACHE_SHARED);
+       attacker_session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+                                                 
SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+                                                 NULL);
+       soup_session_add_feature (attacker_session, SOUP_SESSION_FEATURE 
(attacker_cache));
+
+       attacker_body = do_request (attacker_session, base_uri, "GET", 
"/authz-shared-cache", NULL,
+                                   "Authorization", "Bearer ATTACKER_SECRET",
+                                   "Test-Set-Cache-Control", "max-age=600",
+                                   NULL);
+       g_assert_true (last_request_hit_network);
+
+       soup_cache_dump (attacker_cache);
+       soup_test_session_abort_unref (attacker_session);
+       g_object_unref (attacker_cache);
+
+       victim_cache = soup_cache_new (cache_dir, SOUP_CACHE_SHARED);
+       soup_cache_load (victim_cache);
+       victim_session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+                                               
SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+                                               NULL);
+       soup_session_add_feature (victim_session, SOUP_SESSION_FEATURE 
(victim_cache));
+
+       victim_body = do_request (victim_session, base_uri, "GET", 
"/authz-shared-cache", NULL,
+                                 "Authorization", "Bearer VICTIM_SECRET",
+                                 "Test-Set-Cache-Control", "max-age=600",
+                                 NULL);
+
+       g_assert_true (last_request_hit_network);
+       g_assert_cmpstr (attacker_body, !=, victim_body);
+
+       g_free (attacker_body);
+       g_free (victim_body);
+
+       soup_test_session_abort_unref (victim_session);
+       g_object_unref (victim_cache);
+       g_free (cache_dir);
+}
+
 static guint
 count_cached_resources_in_dir (const char *cache_dir)
 {
@@ -781,6 +839,7 @@ main (int argc, char **argv)
        g_test_add_data_func ("/cache/cancellation", base_uri, do_cancel_test);
        g_test_add_data_func ("/cache/refcounting", base_uri, 
do_refcounting_test);
        g_test_add_data_func ("/cache/headers", base_uri, do_headers_test);
+       g_test_add_data_func ("/cache/shared-cache-authorization", base_uri, 
do_shared_cache_authorization_test);
        g_test_add_data_func ("/cache/leaks", base_uri, do_leaks_test);
 
        ret = g_test_run ();

Reply via email to