[Pkg-freeipa-devel] Bug#1140850: trixie-pu: package python-jwcrypto/1.5.6-1.1~deb13u1
Adrian Bunk
bunk at debian.org
Sat Jun 27 20:00:15 BST 2026
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: python-jwcrypto at packages.debian.org, security at debian.org
Control: affects -1 + src:python-jwcrypto
User: release.debian.org at packages.debian.org
Usertags: pu
* CVE-2026-39373: JWT bomb Attack in deserialize (Closes: #1133006)
-------------- next part --------------
diffstat for python-jwcrypto-1.5.6 python-jwcrypto-1.5.6
changelog | 14
patches/0001-Limit-max-plaintext-size-for-JWE-decompression.patch | 156 ++++++++++
patches/series | 1
3 files changed, 171 insertions(+)
diff -Nru python-jwcrypto-1.5.6/debian/changelog python-jwcrypto-1.5.6/debian/changelog
--- python-jwcrypto-1.5.6/debian/changelog 2024-05-02 09:03:21.000000000 +0300
+++ python-jwcrypto-1.5.6/debian/changelog 2026-06-27 21:49:49.000000000 +0300
@@ -1,3 +1,17 @@
+python-jwcrypto (1.5.6-1.1~deb13u1) trixie; urgency=medium
+
+ * Non-maintainer upload.
+ * Rebuild for trixie.
+
+ -- Adrian Bunk <bunk at debian.org> Sat, 27 Jun 2026 21:49:49 +0300
+
+python-jwcrypto (1.5.6-1.1) unstable; urgency=medium
+
+ * Non-maintainer upload.
+ * CVE-2026-39373: JWT bomb Attack in deserialize (Closes: #1133006)
+
+ -- Adrian Bunk <bunk at debian.org> Tue, 23 Jun 2026 17:17:46 +0300
+
python-jwcrypto (1.5.6-1) unstable; urgency=medium
* New upstream release.
diff -Nru python-jwcrypto-1.5.6/debian/patches/0001-Limit-max-plaintext-size-for-JWE-decompression.patch python-jwcrypto-1.5.6/debian/patches/0001-Limit-max-plaintext-size-for-JWE-decompression.patch
--- python-jwcrypto-1.5.6/debian/patches/0001-Limit-max-plaintext-size-for-JWE-decompression.patch 1970-01-01 02:00:00.000000000 +0200
+++ python-jwcrypto-1.5.6/debian/patches/0001-Limit-max-plaintext-size-for-JWE-decompression.patch 2026-06-23 17:17:46.000000000 +0300
@@ -0,0 +1,156 @@
+From 4c4740f2c8f94793f27c0bfc5689dc28d131da45 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Mon, 6 Apr 2026 10:37:20 -0400
+Subject: Limit max plaintext size for JWE decompression
+
+This change introduces a maximum plaintext size limit (defaulting to 100MB)
+during JWE decryption and updates the decompression logic to enforce it safely
+using zlib.decompressobj. The decrypt method now accepts a max_plaintext
+parameter to allow overriding the default limit.
+
+This mitigates memory exhaustion and decompression bomb attacks when
+processing highly compressed malicious JWE payloads.
+
+Fixes CVE-2026-39373
+
+Signed-off-by: Simo Sorce <simo at redhat.com>
+---
+ jwcrypto/jwe.py | 27 +++++++++++++++++++++------
+ jwcrypto/tests.py | 34 ++++++++++++++++++++++++++--------
+ 2 files changed, 47 insertions(+), 14 deletions(-)
+
+diff --git a/jwcrypto/jwe.py b/jwcrypto/jwe.py
+index 5df500b..613699e 100644
+--- a/jwcrypto/jwe.py
++++ b/jwcrypto/jwe.py
+@@ -12,7 +12,8 @@ from jwcrypto.jwk import JWKSet
+
+ # Limit the amount of data we are willing to decompress by default.
+ default_max_compressed_size = 256 * 1024
+-
++# Limit the maximum plaintext size to 100MB by default.
++default_max_plaintext_size = 100 * 1024 * 1024
+
+ # RFC 7516 - 4.1
+ # name: (description, supported?)
+@@ -371,7 +372,7 @@ class JWE:
+ return data
+
+ # FIXME: allow to specify which algorithms to accept as valid
+- def _decrypt(self, key, ppe):
++ def _decrypt(self, key, ppe, max_plaintext=default_max_plaintext_size):
+
+ jh = self._get_jose_header(ppe.get('header', None))
+
+@@ -429,19 +430,29 @@ class JWE:
+ raise InvalidJWEData(
+ 'Compressed data exceeds maximum allowed'
+ 'size' + f' ({default_max_compressed_size})')
+- self.plaintext = zlib.decompress(data, -zlib.MAX_WBITS)
++ do = zlib.decompressobj(wbits=-zlib.MAX_WBITS)
++ self.plaintext = do.decompress(data, max_plaintext)
++ if do.unconsumed_tail or not do.eof:
++ self.plaintext = None
++ raise InvalidJWEData(
++ 'Compressed data exceeds maximum allowed'
++ 'output size' + f' ({max_plaintext})')
+ elif compress is None:
+ self.plaintext = data
+ else:
+ raise ValueError('Unknown compression')
+
+- def decrypt(self, key):
++ def decrypt(self, key, max_plaintext=0):
+ """Decrypt a JWE token.
+
+ :param key: The (:class:`jwcrypto.jwk.JWK`) decryption key.
+ :param key: A (:class:`jwcrypto.jwk.JWK`) decryption key,
+ or a (:class:`jwcrypto.jwk.JWKSet`) that contains a key indexed
+ by the 'kid' header or (deprecated) a string containing a password.
++ :param max_plaintext: Maximum plaintext size allowed, 0 means
++ the library default applies. Application writers are recommended
++ to set a limit here if they know what is the max plaintext size
++ for their application.
+
+ :raises InvalidJWEOperation: if the key is not a JWK object.
+ :raises InvalidJWEData: if the ciphertext can't be decrypted or
+@@ -449,6 +460,10 @@ class JWE:
+ :raises JWKeyNotFound: if key is a JWKSet and the key is not found.
+ """
+
++ self.plaintext = None
++ if max_plaintext == 0:
++ max_plaintext = default_max_plaintext_size
++
+ if 'ciphertext' not in self.objects:
+ raise InvalidJWEOperation("No available ciphertext")
+ self.decryptlog = []
+@@ -457,14 +472,14 @@ class JWE:
+ if 'recipients' in self.objects:
+ for rec in self.objects['recipients']:
+ try:
+- self._decrypt(key, rec)
++ self._decrypt(key, rec, max_plaintext=max_plaintext)
+ except Exception as e: # pylint: disable=broad-except
+ if isinstance(e, JWKeyNotFound):
+ missingkey = True
+ self.decryptlog.append('Failed: [%s]' % repr(e))
+ else:
+ try:
+- self._decrypt(key, self.objects)
++ self._decrypt(key, self.objects, max_plaintext=max_plaintext)
+ except Exception as e: # pylint: disable=broad-except
+ if isinstance(e, JWKeyNotFound):
+ missingkey = True
+diff --git a/jwcrypto/tests.py b/jwcrypto/tests.py
+index 59049f8..d75761a 100644
+--- a/jwcrypto/tests.py
++++ b/jwcrypto/tests.py
+@@ -2124,18 +2124,36 @@ class ConformanceTests(unittest.TestCase):
+ enc = jwe.JWE(payload.encode('utf-8'),
+ recipient=key,
+ protected=protected_header).serialize(compact=True)
++ check = jwe.JWE()
++ check.deserialize(enc)
+ with self.assertRaises(jwe.InvalidJWEData):
+- check = jwe.JWE()
+- check.deserialize(enc)
+ check.decrypt(key)
+
+- defmax = jwe.default_max_compressed_size
+- jwe.default_max_compressed_size = 1000000000
+- # ensure we can eraise the limit and decrypt
+- check = jwe.JWE()
+- check.deserialize(enc)
++ # raise the limit on compressed token size so we can decrypt
++ defcmax = jwe.default_max_compressed_size
++ jwe.default_max_compressed_size = 10 * 1024 * 1024
++
++ # this passes if we explicitly allow larger plaintext via API
++ check.decrypt(key, max_plaintext=1000000000)
++
++ # this will still fail because the max plaintext length clamps this
++ with self.assertRaises(jwe.InvalidJWEData):
++ check.decrypt(key)
++
++ # ensure that now this can work with changed defaults
++ defpmax = jwe.default_max_plaintext_size
++ jwe.default_max_plaintext_size = 1000000000
+ check.decrypt(key)
+- jwe.default_max_compressed_size = defmax
++
++ # restore limits
++ jwe.default_max_compressed_size = defcmax
++
++ # check that this fails the max compressed header limits
++ with self.assertRaises(jwe.InvalidJWEData):
++ check.decrypt(key)
++
++ # restore plaintext limits
++ jwe.default_max_plaintext_size = defpmax
+
+
+ class JWATests(unittest.TestCase):
+--
+2.47.3
+
diff -Nru python-jwcrypto-1.5.6/debian/patches/series python-jwcrypto-1.5.6/debian/patches/series
--- python-jwcrypto-1.5.6/debian/patches/series 1970-01-01 02:00:00.000000000 +0200
+++ python-jwcrypto-1.5.6/debian/patches/series 2026-06-23 17:17:46.000000000 +0300
@@ -0,0 +1 @@
+0001-Limit-max-plaintext-size-for-JWE-decompression.patch
More information about the Pkg-freeipa-devel
mailing list