Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
169 changes: 169 additions & 0 deletions SPECS/libsoup/CVE-2026-1760.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
From 30b682af333402eeef4fad3acbc865771f85281a Mon Sep 17 00:00:00 2001
From: Carlos Garcia Campos <cgarcia@igalia.com>
Date: Thu, 29 Jan 2026 16:43:28 +0100
Subject: [PATCH] server: close the connection after responsing a request
containing Content-Length and Transfer-Encoding

Closes #475

Upstream Patch Reference: https://gitlab.gnome.org/GNOME/libsoup/-/commit/30b682af333402eeef4fad3acbc865771f85281a.patch
---
libsoup/server/soup-server-io.c | 8 +++
libsoup/soup-message-headers.c | 86 +++++++++++++++------------------
tests/server-test.c | 4 +-
3 files changed, 51 insertions(+), 47 deletions(-)

diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c
index 7e9cc45..9e237a3 100644
--- a/libsoup/server/soup-server-io.c
+++ b/libsoup/server/soup-server-io.c
@@ -599,6 +599,14 @@ parse_headers (SoupServerMessage *msg,
return SOUP_STATUS_BAD_REQUEST;
}

+ /* A server MAY reject a request that contains both Content-Length and
+ * Transfer-Encoding or process such a request in accordance with the
+ * Transfer-Encoding alone. Regardless, the server MUST close the connection
+ * after responding to such a request to avoid the potential attacks
+ */
+ if (*encoding == SOUP_ENCODING_CHUNKED && soup_message_headers_get_one_common (request_headers, SOUP_HEADER_CONTENT_LENGTH))
+ soup_message_headers_replace_common (request_headers, SOUP_HEADER_CONNECTION, "close", TRUE);
+
/* Generate correct context for request */
req_host = soup_message_headers_get_one_common (request_headers, SOUP_HEADER_HOST);
if (req_host && strchr (req_host, '/')) {
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index d71a2cf..c668899 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -155,19 +155,8 @@ soup_message_headers_set (SoupMessageHeaders *hdrs,
{
switch (name) {
case SOUP_HEADER_CONTENT_LENGTH:
- if (hdrs->encoding == SOUP_ENCODING_CHUNKED)
- return;
-
- if (value) {
- char *end;
-
- hdrs->content_length = g_ascii_strtoull (value, &end, 10);
- if (*end)
- hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
- else
- hdrs->encoding = SOUP_ENCODING_CONTENT_LENGTH;
- } else
- hdrs->encoding = -1;
+ case SOUP_HEADER_TRANSFER_ENCODING:
+ hdrs->encoding = -1;
break;
case SOUP_HEADER_CONTENT_TYPE:
g_clear_pointer (&hdrs->content_type, g_free);
@@ -193,21 +182,6 @@ soup_message_headers_set (SoupMessageHeaders *hdrs,
} else
hdrs->expectations = 0;
break;
- case SOUP_HEADER_TRANSFER_ENCODING:
- if (value) {
- /* "identity" is a wrong value according to RFC errata 408,
- * and RFC 7230 does not list it as valid transfer-coding.
- * Nevertheless, the obsolete RFC 2616 stated "identity"
- * as valid, so we can't handle it as unrecognized here
- * for compatibility reasons.
- */
- if (g_ascii_strcasecmp (value, "chunked") == 0)
- hdrs->encoding = SOUP_ENCODING_CHUNKED;
- else if (g_ascii_strcasecmp (value, "identity") != 0)
- hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
- } else
- hdrs->encoding = -1;
- break;
default:
break;
}
@@ -951,30 +925,50 @@ soup_message_headers_foreach (SoupMessageHeaders *hdrs,
SoupEncoding
soup_message_headers_get_encoding (SoupMessageHeaders *hdrs)
{
- const char *header;
+ const char *content_length;
+ const char *transfer_encoding;

if (hdrs->encoding != -1)
return hdrs->encoding;

- /* If Transfer-Encoding was set, hdrs->encoding would already
- * be set. So we don't need to check that possibility.
- */
- header = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
- if (header) {
- soup_message_headers_set (hdrs, SOUP_HEADER_CONTENT_LENGTH, header);
- if (hdrs->encoding != -1)
- return hdrs->encoding;
+ /* Transfer-Encoding is checked first because it overrides the Content-Length */
+ transfer_encoding = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING);
+ if (transfer_encoding) {
+ /* "identity" is a wrong value according to RFC errata 408,
+ * and RFC 7230 does not list it as valid transfer-coding.
+ * Nevertheless, the obsolete RFC 2616 stated "identity"
+ * as valid, so we can't handle it as unrecognized here
+ * for compatibility reasons.
+ */
+ if (g_ascii_strcasecmp (transfer_encoding, "chunked") == 0)
+ hdrs->encoding = SOUP_ENCODING_CHUNKED;
+ else if (g_ascii_strcasecmp (transfer_encoding, "identity") != 0)
+ hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
+ } else {
+ content_length = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
+ if (content_length) {
+ char *end;
+
+ hdrs->content_length = g_ascii_strtoull (content_length, &end, 10);
+ if (*end)
+ hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
+ else
+ hdrs->encoding = SOUP_ENCODING_CONTENT_LENGTH;
+ }
+ }
+
+ if (hdrs->encoding == -1) {
+ /* Per RFC 2616 4.4, a response body that doesn't indicate its
+ * encoding otherwise is terminated by connection close, and a
+ * request that doesn't indicate otherwise has no body. Note
+ * that SoupMessage calls soup_message_headers_set_encoding()
+ * to override the response body default for our own
+ * server-side messages.
+ */
+ hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
+ SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
}

- /* Per RFC 2616 4.4, a response body that doesn't indicate its
- * encoding otherwise is terminated by connection close, and a
- * request that doesn't indicate otherwise has no body. Note
- * that SoupMessage calls soup_message_headers_set_encoding()
- * to override the response body default for our own
- * server-side messages.
- */
- hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
- SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
return hdrs->encoding;
}

diff --git a/tests/server-test.c b/tests/server-test.c
index b8f09d3..292dcef 100644
--- a/tests/server-test.c
+++ b/tests/server-test.c
@@ -1317,7 +1317,9 @@ do_chunked_test (ServerData *sd, gconstpointer test_data)
const char *description;
const char *test;
} tests[] = {
- { "Lone LF", "Transfer-Encoding: chunked\r\n\r\n5;ext\n data\r\n0\r\n\r\n" },
+ { "Single LF", "Transfer-Encoding: chunked\r\n\r\n5;ext\n data\r\n0\r\n\r\n" },
+ { "Content-Length and Transfer-Encoding", "Content-Length: 4\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n" },
+ { "Content-Length and Transfer-Encoding with keep alive connection", "Content-Length: 4\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\n\r\n0\r\n\r\n" },
};

sd->server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
--
2.45.4

31 changes: 31 additions & 0 deletions SPECS/libsoup/CVE-2026-2369.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
From 7f618da093133bf7ff5821c74a13a800a6cf6452 Mon Sep 17 00:00:00 2001
From: Samuel Dainard <>
Date: Wed, 11 Feb 2026 10:19:04 -0600
Subject: [PATCH] sniffer: Handle potential underflow

Closes #498

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://gitlab.gnome.org/GNOME/libsoup/-/commit/af4bde990270b825b7d110a495cc65de9e2ec32f.patch
---
libsoup/content-sniffer/soup-content-sniffer.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/libsoup/content-sniffer/soup-content-sniffer.c b/libsoup/content-sniffer/soup-content-sniffer.c
index 3d0e831..914b5b4 100644
--- a/libsoup/content-sniffer/soup-content-sniffer.c
+++ b/libsoup/content-sniffer/soup-content-sniffer.c
@@ -521,6 +521,10 @@ sniff_unknown (SoupContentSniffer *sniffer, GBytes *buffer,
if (!sniff_scriptable && type_row->scriptable)
continue;

+ /* Ensure we have data to sniff - prevents underflow in resource_length - 1 */
+ if (resource_length == 0)
+ continue;
+
if (type_row->has_ws) {
guint index_stream = 0;
guint index_pattern = 0;
--
2.45.4

Loading
Loading