diff mbox series

[meta-python,wrynose,2/7] python3-aiohttp: fix CVE-2026-111750

Message ID 20261106072702.502813-3-dkelaiya@cisco.com
State New
Headers show
Series python3-aiohttp: Security fixes | expand

Commit Message

From: Darsh Kelaiya <dkelaiya@cisco.com>

Backport the upstream HEAD request parsing fix [1] to aiohttp 3.13.5,
as identified by [2]. Only responses to HEAD may skip their body;
incoming HEAD requests must consume the declared request body.

Retain the upstream regression that embeds a request in a HEAD body
and verifies that the following request remains correctly framed.
The pure-Python parser remains available with extensions installed.

[1] https://github.com/aio-libs/aiohttp/commit/9b27347e61454d9f8ca2055f4c67a37dee336e83
[2] https://github.com/aio-libs/aiohttp/security/advisories/GHSA-pqxq-w44r-73xw

Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
---
 .../python3-aiohttp/CVE-2026-111750.patch     | 83 +++++++++++++++++++
 .../python/python3-aiohttp_3.13.5.bb          |  1 +
 2 files changed, 84 insertions(+)
 create mode 100644 meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-111750.patch
diff mbox series

Patch

diff --git a/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-111750.patch b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-111750.patch
new file mode 100644
index 0000000000..61498e09f3
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-111750.patch
@@ -0,0 +1,83 @@ 
+From 9b27347e61454d9f8ca2055f4c67a37dee336e83 Mon Sep 17 00:00:00 2001
+From: Sam Bull <git@sambull.org>
+Date: Wed, 9 Sep 2026 01:25:13 +0100
+Subject: [PATCH] Fix head request parsing (#13671) (#13673)
+
+(cherry picked from commit 5789546e37fe35af27d0a2f840870b22bc15bfc4)
+
+CVE: CVE-2026-111750
+Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/9b27347e61454d9f8ca2055f4c67a37dee336e83]
+
+Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
+---
+ CHANGES/13671.bugfix.rst  |  1 +
+ aiohttp/http_parser.py    |  6 +++++-
+ tests/test_http_parser.py | 27 ++++++++++++++++++++++++++-
+ 3 files changed, 32 insertions(+), 2 deletions(-)
+ create mode 100644 CHANGES/13671.bugfix.rst
+
+diff --git a/CHANGES/13671.bugfix.rst b/CHANGES/13671.bugfix.rst
+new file mode 100644
+index 0000000..e6fbc70
+--- /dev/null
++++ b/CHANGES/13671.bugfix.rst
+@@ -0,0 +1 @@
++Fixed pure-Python request parser not reading a body in a ``HEAD`` request -- by :user:`Dreamsorcerer`.
+diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py
+index f4458dc..ce15764 100644
+--- a/aiohttp/http_parser.py
++++ b/aiohttp/http_parser.py
+@@ -426,8 +426,12 @@ class HttpParser(abc.ABC, Generic[_MsgT]):
+ 
+                         assert self.protocol is not None
+                         # calculate payload
++                        # https://www.rfc-editor.org/info/rfc9112/#name-message-body-length
++                        # https://www.rfc-editor.org/info/rfc9110/#section-9.3.1-6
++                        # EMPTY_BODY_METHODS should only apply to responses.
++                        # self.method is None on request parser.
+                         empty_body = code in EMPTY_BODY_STATUS_CODES or bool(
+-                            method and method in EMPTY_BODY_METHODS
++                            self.method and self.method in EMPTY_BODY_METHODS
+                         )
+                         if not empty_body and (
+                             (length is not None and length > 0) or msg.chunked
+diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py
+index 4cdd94c..4255f4d 100644
+--- a/tests/test_http_parser.py
++++ b/tests/test_http_parser.py
+@@ -1781,7 +1781,32 @@ def test_http_request_chunked_payload_and_next_message(parser) -> None:
+     assert not payload2.is_eof()
+ 
+ 
+-def test_http_request_chunked_payload_chunks(parser) -> None:
++def test_http_request_parser_head_with_content_length_payload(
++    parser: HttpRequestParser,
++) -> None:
++    smuggled = b"GET /smuggled HTTP/1.1\r\nHost: a\r\n\r\n"
++    text = (
++        b"HEAD /test HTTP/1.1\r\nHost: a\r\nContent-Length: %d\r\n\r\n" % len(smuggled)
++        + smuggled
++        + b"POST /next HTTP/1.1\r\nHost: a\r\nContent-Length: 0\r\n\r\n"
++    )
++    messages, upgraded, tail = parser.feed_data(text)
++
++    assert len(messages) == 2
++    msg, payload = messages[0]
++    assert msg.method == "HEAD"
++    assert b"".join(payload._buffer) == smuggled
++    assert payload.is_eof()
++
++    msg2, payload2 = messages[1]
++    assert msg2.method == "POST"
++    assert msg2.path == "/next"
++    assert payload2.is_eof()
++    assert not upgraded
++    assert not tail
++
++
++def test_http_request_chunked_payload_chunks(parser: HttpRequestParser) -> None:
+     text = b"GET /test HTTP/1.1\r\ntransfer-encoding: chunked\r\n\r\n"
+     msg, payload = parser.feed_data(text)[0][0]
+ 
+-- 
+2.35.6
diff --git a/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb b/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb
index 917405c715..40ac847c01 100644
--- a/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb
+++ b/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb
@@ -24,6 +24,7 @@  SRC_URI += " \
     file://CVE-2026-69244.patch \
     file://CVE-2026-111066_p1.patch \
     file://CVE-2026-111066_p2.patch \
+    file://CVE-2026-111750.patch \
 "
 
 CVE_PRODUCT = "aiohttp:aiohttp"