new file mode 100644
@@ -0,0 +1,157 @@
+From 2bdcc44d1e163fb5cc48a8662425e35e15adfe6a Mon Sep 17 00:00:00 2001
+From: Illia Volochii <illia.volochii@gmail.com>
+Date: Thu, 7 May 2026 18:39:03 +0300
+Subject: [PATCH] Merge commit from fork
+
+* Avoid any decoding in `HTTPResponse.drain_conn`
+
+* Add a comment
+
+* Simplify `drain_conn`
+
+* Add tests
+
+* Add additional checks to the test
+
+* Fix full decompression on the 2nd small read from response using Brotli
+
+* Add a changelog entry
+
+* Inverse the order in the changelog entry
+
+* Mention `stream` call
+
+CVE: CVE-2026-44432
+Upstream-Status: Backport [https://github.com/urllib3/urllib3/commit/2bdcc44d1e163fb5cc48a8662425e35e15adfe6a]
+
+Backport Changes:
+- Omitted changelog/GHSA-mf9v-mfxr-j63j.bugfix.rst because the OE recipe
+ backport applies the runtime fix and tests; the package does not ship it.
+
+Signed-off-by: Yogita Urade <yurade@cisco.com>
+---
+ src/urllib3/response.py | 17 +++++++++++------
+ test/test_response.py | 24 +++++++++++++++++++++---
+ test/with_dummyserver/test_connection.py | 19 +++++++++++++++++++
+ 3 files changed, 51 insertions(+), 9 deletions(-)
+
+diff --git a/src/urllib3/response.py b/src/urllib3/response.py
+index 521c31b282..e9246b75e3 100644
+--- a/src/urllib3/response.py
++++ b/src/urllib3/response.py
+@@ -798,13 +798,14 @@ def drain_conn(self) -> None:
+ Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
+ """
+ try:
+- self.read(
+- # Do not spend resources decoding the content unless
+- # decoding has already been initiated.
+- decode_content=self._has_decoded_content,
+- )
++ self._raw_read()
+ except (HTTPError, OSError, BaseSSLError, HTTPException):
+ pass
++ if self._has_decoded_content:
++ # `_raw_read` skips decompression, so we should clean up the
++ # decoder to avoid keeping unnecessary data in memory.
++ self._decoded_buffer = BytesQueueBuffer()
++ self._decoder = None
+
+ @property
+ def data(self) -> bytes:
+@@ -1091,7 +1092,11 @@ def read(
+ elif amt is not None:
+ cache_content = False
+
+- if self._decoder and self._decoder.has_unconsumed_tail:
++ if (
++ self._decoder
++ and self._decoder.has_unconsumed_tail
++ and len(self._decoded_buffer) < amt
++ ):
+ decoded_data = self._decode(
+ b"",
+ decode_content,
+
+diff --git a/test/test_response.py b/test/test_response.py
+index c70262c04e..da521137bf 100644
+--- a/test/test_response.py
++++ b/test/test_response.py
+@@ -858,22 +858,33 @@ def test_memory_usage_decode_with_max_length(
+ pytest.skip(f"Proper {request.node.callspec.id} decoder is not available")
+
+ name, compressed_data = data
+- limit = 1024 * 1024 # 1 MiB
++ limit1 = 1024 * 1024 # 1 MiB
++ # We test with two read calls because the second call may be
++ # able to use the internal buffer filled by the first call, and
++ # we want to ensure that full decompression is never triggered
++ # by the second call. The limit for the second call is lowered
++ # to make sure that the internal buffer is used for the Brotli
++ # case specifically https://github.com/google/brotli/issues/1396
++ limit2 = 1024 # 1 KiB
+ if read_method in ("read_chunked", "stream"):
+ httplib_r = httplib.HTTPResponse(MockSock) # type: ignore[arg-type]
++ httplib_r.chunked = True
++ httplib_r.chunk_left = 1
+ httplib_r.fp = MockChunkedEncodingResponse([compressed_data]) # type: ignore[assignment]
+ r = HTTPResponse(
+ httplib_r,
+ preload_content=False,
+ headers={"transfer-encoding": "chunked", "content-encoding": name},
+ )
+- next(getattr(r, read_method)(amt=limit, decode_content=True))
++ for limit in (limit1, limit2):
++ next(getattr(r, read_method)(amt=limit, decode_content=True))
+ else:
+ fp = BytesIO(compressed_data)
+ r = HTTPResponse(
+ fp, headers={"content-encoding": name}, preload_content=False
+ )
+- getattr(r, read_method)(amt=limit, decode_content=True)
++ for limit in (limit1, limit2):
++ getattr(r, read_method)(amt=limit, decode_content=True)
+
+ # Check that the internal decoded buffer is empty unless brotli
+ # is used.
+@@ -883,6 +894,13 @@ def test_memory_usage_decode_with_max_length(
+ if name != "br" or brotli.__name__ == "brotlicffi":
+ assert len(r._decoded_buffer) == 0
+
++ # Check that memory usage is still within the limit while the
++ # connection is being drained, meaning that the call does not
++ # decompress the whole content.
++ r.drain_conn()
++ assert r._decoder is None
++ assert len(r._decoded_buffer) == 0
++
+ def test_multi_decoding_deflate_deflate(self) -> None:
+ data = zlib.compress(zlib.compress(b"foo"))
+
+diff --git a/test/with_dummyserver/test_connection.py b/test/with_dummyserver/test_connection.py
+index b9c547c00f..940815dac2 100644
+--- a/test/with_dummyserver/test_connection.py
++++ b/test/with_dummyserver/test_connection.py
+@@ -138,3 +138,22 @@ def test_invalid_tunnel_scheme(pool: HTTPConnectionPool) -> None:
+ str(e.value)
+ == "Invalid proxy scheme for tunneling: 'socks', must be either 'http' or 'https'"
+ )
++
++
++def test_response_after_drain_conn(pool: HTTPConnectionPool) -> None:
++ """
++ Test that a connection can be reused after calling `drain_conn` on
++ an unread response.
++ """
++ conn = pool._get_conn()
++
++ conn.request("GET", "/", preload_content=False)
++ response = conn.getresponse()
++ assert response.status == 200
++ response.drain_conn()
++
++ conn.request("GET", "/", preload_content=False)
++ response = conn.getresponse()
++ assert response.status == 200
++
++ conn.close()
@@ -5,6 +5,7 @@ LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=52d273a3054ced561275d4d15260ecda"
SRC_URI += "file://CVE-2026-44431.patch \
file://CVE-2026-97689.patch \
+ file://CVE-2026-44432.patch \
"
SRC_URI[sha256sum] = "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"
This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/urllib3/urllib3/commit/2bdcc44d1e163fb5cc48a8662425e35e15adfe6a [2] https://security-tracker.debian.org/tracker/CVE-2026-44432 Signed-off-by: Yogita Urade <yurade@cisco.com> --- .../python3-urllib3/CVE-2026-44432.patch | 157 ++++++++++++++++++ .../python/python3-urllib3_2.6.3.bb | 1 + 2 files changed, 158 insertions(+) create mode 100644 meta/recipes-devtools/python/python3-urllib3/CVE-2026-44432.patch