CVE-2024-28102 (published 2024-03-21T02:52Z)

JWCrypto implements JWK, JWS, and JWE specifications using python-cryptography. Prior to version 1.5.6, an attacker can cause a denial of service attack by passing in a malicious JWE Token with a high compression ratio. When the server processes this token, it will consume a lot of memory and processing time. Version 1.5.6 fixes this vulnerability by limiting the maximum token length.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/latchset/jwcrypto
commit_details: repo_url: https://github.com/latchset/jwcrypto
author: Simo Sorce
author_date: 2024-03-05 16:57:17-05:00
msg: Address potential DoS with high compression ratio

Fixes CVE-2024-28102

Signed-off-by: Simo Sorce <simo@redhat.com>
repository: repo_url: https://github.com/latchset/jwcrypto
repo_name: latchset/jwcrypto
description: Implements JWK,JWS,JWE specifications using python-cryptography
repo_language: Python
owner: latchset
file_changes: filename: jwe.py
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,9 @@ from jwcrypto.common import json_decode, json_encode
 from jwcrypto.jwa import JWA
 from jwcrypto.jwk import JWKSet
 
+# Limit the amount of data we are willing to decompress by default.
+default_max_compressed_size = 256 * 1024
+
 
 # RFC 7516 - 4.1
 # name: (description, supported?)
@@ -422,6 +425,10 @@ class JWE:
 
         compress = jh.get('zip', None)
         if compress == 'DEF':
+            if len(data) > default_max_compressed_size:
+                raise InvalidJWEData(
+                    'Compressed data exceeds maximum allowed'
+                    'size' + f' ({default_max_compressed_size})')
             self.plaintext = zlib.decompress(data, -zlib.MAX_WBITS)
         elif compress is None:
             self.plaintext = data

programming_language: Python
filename: tests.py
change_type: ModificationType.MODIFY
diff: @@ -2111,6 +2111,32 @@ class ConformanceTests(unittest.TestCase):
         jwa.default_max_pbkdf2_iterations += 2
         p2cenc.add_recipient(key)
 
+    def test_jwe_decompression_max(self):
+        key = jwk.JWK(kty='oct', k=base64url_encode(b'A' * (128 // 8)))
+        payload = '{"u": "' + "u" * 400000000 + '", "uu":"' \
+            + "u" * 400000000 + '"}'
+        protected_header = {
+            "alg": "A128KW",
+            "enc": "A128GCM",
+            "typ": "JWE",
+            "zip": "DEF",
+        }
+        enc = jwe.JWE(payload.encode('utf-8'),
+                      recipient=key,
+                      protected=protected_header).serialize(compact=True)
+        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)
+        check.decrypt(key)
+        jwe.default_max_compressed_size = defmax
+
 
 class JWATests(unittest.TestCase):
     def test_jwa_create(self):

programming_language: Python