diff --git a/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-41608.patch b/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-41608.patch
new file mode 100644
index 0000000000..a65f0ac73b
--- /dev/null
+++ b/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-41608.patch
@@ -0,0 +1,176 @@
+From d6ef4cd811666ce8c72dd5417d95debce52f490b Mon Sep 17 00:00:00 2001
+From: Jens Geyer <jensg@apache.org>
+Date: Sun, 19 Apr 2026 10:10:35 +0200
+Subject: [PATCH] Add decompressed payload size limit to Python
+ THeaderTransport Client: py
+
+Adds _max_decompressed_size (default: HARD_MAX_FRAME_SIZE) and
+set_max_decompressed_size() to THeaderTransport. ZLIB decompression
+now uses decompressobj with a size cap instead of unbounded
+zlib.decompress(), consistent with the C++ implementation.
+
+Refactor THeaderTransport read-transform dispatch into _apply_read_transform
+
+Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
+
+CVE: CVE-2026-41608
+Upstream-Status: Backport [https://github.com/apache/thrift/commit/8c605880ea4ef050a689c859de3b702ad8d4ce7b]
+
+Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
+---
+ lib/py/src/transport/THeaderTransport.py | 26 +++++++---
+ lib/py/test/thrift_transport.py          | 65 ++++++++++++++++++++++++
+ 2 files changed, 85 insertions(+), 6 deletions(-)
+
+diff --git a/lib/py/src/transport/THeaderTransport.py b/lib/py/src/transport/THeaderTransport.py
+index 4fb203430..51bc43cf7 100644
+--- a/lib/py/src/transport/THeaderTransport.py
++++ b/lib/py/src/transport/THeaderTransport.py
+@@ -60,9 +60,7 @@ class THeaderTransformID(object):
+     ZLIB = 0x01
+ 
+ 
+-READ_TRANSFORMS_BY_ID = {
+-    THeaderTransformID.ZLIB: zlib.decompress,
+-}
++KNOWN_READ_TRANSFORM_IDS = frozenset({THeaderTransformID.ZLIB})
+ 
+ 
+ WRITE_TRANSFORMS_BY_ID = {
+@@ -102,6 +100,7 @@ class THeaderTransport(TTransportBase, CReadableTransport):
+         self.sequence_id = 0
+         self._protocol_id = default_protocol
+         self._max_frame_size = HARD_MAX_FRAME_SIZE
++        self._max_decompressed_size = HARD_MAX_FRAME_SIZE
+ 
+     def isOpen(self):
+         return self._transport.isOpen()
+@@ -135,6 +134,22 @@ class THeaderTransport(TTransportBase, CReadableTransport):
+             raise ValueError("maximum frame size should be < %d and > 0" % HARD_MAX_FRAME_SIZE)
+         self._max_frame_size = size
+ 
++    def set_max_decompressed_size(self, size):
++        if not 0 < size <= HARD_MAX_FRAME_SIZE:
++            raise ValueError("maximum decompressed size should be <= %d and > 0" % HARD_MAX_FRAME_SIZE)
++        self._max_decompressed_size = size
++
++    def _apply_read_transform(self, transform_id, payload):
++        if transform_id == THeaderTransformID.ZLIB:
++            decompressor = zlib.decompressobj()
++            payload = decompressor.decompress(payload, self._max_decompressed_size)
++            if decompressor.unconsumed_tail:
++                raise TTransportException(
++                    TTransportException.SIZE_LIMIT,
++                    "Decompressed payload exceeds maximum allowed size.",
++                )
++        return payload
++
+     @property
+     def protocol_id(self):
+         if self._client_type == THeaderClientType.HEADERS:
+@@ -250,7 +265,7 @@ class THeaderTransport(TTransportBase, CReadableTransport):
+         transform_count = readVarint(buffer_transport)
+         for _ in range(transform_count):
+             transform_id = readVarint(buffer_transport)
+-            if transform_id not in READ_TRANSFORMS_BY_ID:
++            if transform_id not in KNOWN_READ_TRANSFORM_IDS:
+                 raise TApplicationException(
+                     TApplicationException.INVALID_TRANSFORM,
+                     "Unknown transform: %d" % transform_id,
+@@ -276,8 +291,7 @@ class THeaderTransport(TTransportBase, CReadableTransport):
+ 
+         payload = buffer.read()
+         for transform_id in transforms:
+-            transform_fn = READ_TRANSFORMS_BY_ID[transform_id]
+-            payload = transform_fn(payload)
++            payload = self._apply_read_transform(transform_id, payload)
+         return BytesIO(payload)
+ 
+     def write(self, buf):
+diff --git a/lib/py/test/thrift_transport.py b/lib/py/test/thrift_transport.py
+index cb1bb0ce7..cb0d815cb 100644
+--- a/lib/py/test/thrift_transport.py
++++ b/lib/py/test/thrift_transport.py
+@@ -17,11 +17,17 @@
+ # under the License.
+ #
+ 
++import struct
+ import unittest
++import zlib
+ import os
+ 
+ import _import_local_thrift  # noqa
+ from thrift.transport import TTransport
++from thrift.transport.THeaderTransport import (
++    THeaderTransport, THeaderClientType, THeaderTransformID, HEADER_MAGIC,
++)
++from thrift.transport.TTransport import TTransportException
+ 
+ 
+ class TestTFileObjectTransport(unittest.TestCase):
+@@ -66,5 +72,64 @@ class TestMemoryBuffer(unittest.TestCase):
+         buffer_r.close()
+ 
+ 
++def _craft_zlib_header_frame(plain_payload):
++    """Return a complete THeaderTransport frame with a ZLIB-compressed payload."""
++    compressed = zlib.compress(plain_payload)
++    # proto_id=0, 1 transform; values <128 encode as single varint bytes
++    hdr_content = bytes([0, 1, THeaderTransformID.ZLIB])
++    padding = (4 - len(hdr_content) % 4) % 4
++    hdr_bytes = hdr_content + b'\x00' * padding
++    header_len_u16 = len(hdr_bytes) // 4
++    # 10 fixed bytes: 2(magic)+2(flags)+4(seqid)+2(hdr_len_u16)
++    frame_size = 10 + len(hdr_bytes) + len(compressed)
++    frame = struct.pack('!i', frame_size)
++    frame += struct.pack('!H', HEADER_MAGIC)
++    frame += struct.pack('!H', 0)   # flags
++    frame += struct.pack('!i', 0)   # sequence_id
++    frame += struct.pack('!H', header_len_u16)
++    frame += hdr_bytes
++    frame += compressed
++    return frame
++
++
++class TestTHeaderTransportDecompressionLimit(unittest.TestCase):
++
++    def _make_transport(self, payload, max_decompressed_size=None):
++        frame = _craft_zlib_header_frame(payload)
++        inner = TTransport.TMemoryBuffer(frame)
++        transport = THeaderTransport(inner, [THeaderClientType.HEADERS])
++        if max_decompressed_size is not None:
++            transport.set_max_decompressed_size(max_decompressed_size)
++        return transport
++
++    def test_zlib_roundtrip(self):
++        payload = b'Hello Thrift! ' * 100
++        t = self._make_transport(payload)
++        t.readFrame(1)
++        self.assertEqual(t._read_buffer.read(), payload)
++
++    def test_decompression_bomb_blocked(self):
++        # 10,000 bytes decompressed; limit set to 1,000
++        payload = b'A' * 10000
++        t = self._make_transport(payload, max_decompressed_size=1000)
++        with self.assertRaises(TTransportException) as ctx:
++            t.readFrame(1)
++        self.assertEqual(ctx.exception.type, TTransportException.SIZE_LIMIT)
++
++    def test_payload_at_limit_passes(self):
++        payload = b'B' * 5000
++        t = self._make_transport(payload, max_decompressed_size=5000)
++        t.readFrame(1)
++        self.assertEqual(t._read_buffer.read(), payload)
++
++    def test_set_max_decompressed_size_rejects_invalid(self):
++        inner = TTransport.TMemoryBuffer(b'')
++        t = THeaderTransport(inner, [THeaderClientType.HEADERS])
++        with self.assertRaises(ValueError):
++            t.set_max_decompressed_size(0)
++        with self.assertRaises(ValueError):
++            t.set_max_decompressed_size(-1)
++
++
+ if __name__ == '__main__':
+     unittest.main()
diff --git a/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb b/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb
index 0128de8519..b5dee9bd00 100644
--- a/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb
+++ b/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb
@@ -17,6 +17,7 @@ SRC_URI = "https://downloads.apache.org/${BPN}/${PV}/${BP}.tar.gz \
            file://CVE-2026-58023.patch \
            file://CVE-2026-48144.patch \
            file://CVE-2026-58389.patch \
+           file://CVE-2026-41608.patch \
            "
 SRC_URI[sha256sum] = "794a0e455787960d9f27ab92c38e34da27e8deeda7a5db0e59dc64a00df8a1e5"
 
