joserfc PBES2 p2c Unbounded Iteration Count enables Denial of Service (DoS)
Description
joserfc is a Python library that provides an implementation of several JSON Object Signing and Encryption (JOSE) standards. In 1.6.2 and earlier, a resource exhaustion vulnerability in joserfc allows an unauthenticated attacker to cause a Denial of Service (DoS) via CPU exhaustion. When the library decrypts a JSON Web Encryption (JWE) token using Password-Based Encryption (PBES2) algorithms, it reads the p2c (PBES2 Count) parameter directly from the token's protected header. This parameter defines the number of iterations for the PBKDF2 key derivation function. Because joserfc does not validate or bound this value, an attacker can specify an extremely large iteration count (e.g., 2^31 - 1), forcing the server to expend massive CPU resources processing a single token. This vulnerability exists at the JWA layer and impacts all high-level JWE and JWT decryption interfaces if PBES2 algorithms are allowed by the application's policy.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2026-27932: In joserfc <=1.6.2, unauthenticated attackers cause CPU exhaustion by providing an unbounded PBES2 iteration count in JWE tokens.
Vulnerability
Description CVE-2026-27932 is a resource exhaustion vulnerability in the Python joserfc library (versions 1.6.2 and earlier). The issue lies in how the library processes Password-Based Encryption (PBES2) algorithms during JWE decryption. Specifically, the p2c (PBES2 Count) parameter in a JWE token's protected header, which controls the number of PBKDF2 iterations, is taken directly from the attacker-controlled token without any validation or upper bound [1][2]. The vulnerable code path is in the PBES2HSAlgKeyEncryption.decrypt_cek() function, which passes the p2c value straight into the PBKDF2HMAC constructor [2].
Attack
Vector and Exploitation An unauthenticated attacker can exploit this by crafting a JWE token with an arbitrarily large p2c value (e.g., 2^31 - 1) and sending it to any server that uses joserfc with PBES2 algorithms enabled. The server will then compute an extremely expensive PBKDF2 key derivation, consuming massive CPU resources before any token validation (such as expiration or signature checks) occurs [2]. This makes the attack trivially accessible to any network-entity that can deliver HTTP requests to the vulnerable endpoint.
Impact
The primary impact is a Denial of Service (DoS) via CPU exhaustion. A single malicious token can tie up server resources for an extended period, potentially degrading or halting service for legitimate users [1][2]. Because the vulnerability operates at the JWA layer, it affects all high-level JWE and JWT decryption interfaces, meaning any application policy that permits PBES2 algorithms is immediately at risk [2].
Mitigation
The joserfc maintainers have released a fix in commit 696a961, which introduces a validate_p2c function that enforces a maximum iteration count of 300,000 (and warns if below 1,000) [3][4]. Users should update to a patched version or apply the commit's changes manually. As a workaround, applications can disable PBES2 key management algorithms in their JWT policies until the update is applied [1][2].
AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
joserfcPyPI | < 1.6.3 | 1.6.3 |
Affected products
2- authlib/joserfcv5Range: <= 1.6.2
Patches
2696a9611ab98fix(jwe): set max value for p2c
2 files changed · +62 −2
src/joserfc/_rfc7518/jwe_algs.py+17 −2 modified@@ -1,5 +1,7 @@ from __future__ import annotations import secrets +import warnings + from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.keywrap import ( @@ -30,6 +32,7 @@ from ..errors import ( InvalidKeyLengthError, DecodeError, + SecurityWarning, ) @@ -224,16 +227,28 @@ def decrypt_agreed_upon_key(self, enc: JWEEncModel, recipient: Recipient[ECKey]) return derive_key_for_concat_kdf(shared_key, headers, enc.cek_size, self.key_size) +def validate_p2c(value: int) -> None: + if not isinstance(value, int): + raise ValueError("must be an int") + + # A minimum iteration count of 1000 is RECOMMENDED. + if value < 1000: + warnings.warn("A minimum iteration count of 1000 is RECOMMENDED", SecurityWarning) + + max_value = 300000 + if value > max_value: + raise ValueError(f"must be less than {max_value}") + + class PBES2HSAlgKeyEncryption(JWEKeyEncryption): # https://www.rfc-editor.org/rfc/rfc7518#section-4.8 key_size: int more_header_registry = { "p2s": HeaderParameter("PBES2 Salt Input", "str", True), - "p2c": HeaderParameter("PBES2 Count", "int", True), + "p2c": HeaderParameter("PBES2 Count", validate_p2c, True), } key_types = ["oct"] - # A minimum iteration count of 1000 is RECOMMENDED. DEFAULT_P2C = 2048 def __init__(self, hash_size: int, key_wrapping: JWEKeyWrapping):
tests/jwe/test_compact.py+45 −0 modified@@ -8,6 +8,7 @@ from joserfc.jwa import JWE_ENC_MODELS from joserfc.jwk import RSAKey, ECKey, OctKey, OKPKey, KeySet from joserfc.errors import ( + SecurityWarning, InvalidKeyLengthError, MissingAlgorithmError, MissingEncryptionError, @@ -180,6 +181,50 @@ def test_PBES2HS_with_header(self): registry=registry, ) + def test_PBES2HS_with_small_p2c(self): + key = OctKey.generate_key(128) + protected = { + "alg": "PBES2-HS256+A128KW", + "enc": "A128CBC-HS256", + "p2s": "QoGrcBpns_cLWCQPEVuA-g", + "p2c": 500, + } + registry = JWERegistry(algorithms=["PBES2-HS256+A128KW", "A128CBC-HS256"]) + self.assertWarns( + SecurityWarning, + encrypt_compact, + protected, + b"i", + key, + registry=registry, + ) + + def test_PBES2HS_with_large_p2c(self): + key = OctKey.import_key({"k": "pyL42ncDFSYnenl-GiZjRw", "kty": "oct"}) + protected = { + "alg": "PBES2-HS256+A128KW", + "enc": "A128CBC-HS256", + "p2s": "QoGrcBpns_cLWCQPEVuA-g", + "p2c": 500000, + } + registry = JWERegistry(algorithms=["PBES2-HS256+A128KW", "A128CBC-HS256"]) + self.assertRaises( + InvalidHeaderValueError, + encrypt_compact, + protected, + b"i", + key, + registry=registry, + ) + encrypted = "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwicDJzIjoiUW9HcmNCcG5zX2NMV0NRUEVWdUEtZyIsInAyYyI6NTAwMDAwfQ.qdtshVQlPM-fW57DRVUnmwMyvBVzUZCm58zn7j5W7IP9S2-cBVTh_w.mMUagTUTRi7fLQ3VUi6g4w.Hi0-8_MusxEwRtW6dkjXzw.Ktm1FmBA9rPe0Vv8w0kZ2g" + self.assertRaises( + InvalidHeaderValueError, + decrypt_compact, + encrypted, + key, + registry=registry, + ) + def test_with_zip_header(self): private_key: RSAKey = load_key("rsa-openssl-private.pem") public_key: RSAKey = load_key("rsa-openssl-public.pem")
696a961fix(jwe): set max value for p2c
2 files changed · +62 −2
src/joserfc/_rfc7518/jwe_algs.py+17 −2 modified@@ -1,5 +1,7 @@ from __future__ import annotations import secrets +import warnings + from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.keywrap import ( @@ -30,6 +32,7 @@ from ..errors import ( InvalidKeyLengthError, DecodeError, + SecurityWarning, ) @@ -224,16 +227,28 @@ def decrypt_agreed_upon_key(self, enc: JWEEncModel, recipient: Recipient[ECKey]) return derive_key_for_concat_kdf(shared_key, headers, enc.cek_size, self.key_size) +def validate_p2c(value: int) -> None: + if not isinstance(value, int): + raise ValueError("must be an int") + + # A minimum iteration count of 1000 is RECOMMENDED. + if value < 1000: + warnings.warn("A minimum iteration count of 1000 is RECOMMENDED", SecurityWarning) + + max_value = 300000 + if value > max_value: + raise ValueError(f"must be less than {max_value}") + + class PBES2HSAlgKeyEncryption(JWEKeyEncryption): # https://www.rfc-editor.org/rfc/rfc7518#section-4.8 key_size: int more_header_registry = { "p2s": HeaderParameter("PBES2 Salt Input", "str", True), - "p2c": HeaderParameter("PBES2 Count", "int", True), + "p2c": HeaderParameter("PBES2 Count", validate_p2c, True), } key_types = ["oct"] - # A minimum iteration count of 1000 is RECOMMENDED. DEFAULT_P2C = 2048 def __init__(self, hash_size: int, key_wrapping: JWEKeyWrapping):
tests/jwe/test_compact.py+45 −0 modified@@ -8,6 +8,7 @@ from joserfc.jwa import JWE_ENC_MODELS from joserfc.jwk import RSAKey, ECKey, OctKey, OKPKey, KeySet from joserfc.errors import ( + SecurityWarning, InvalidKeyLengthError, MissingAlgorithmError, MissingEncryptionError, @@ -180,6 +181,50 @@ def test_PBES2HS_with_header(self): registry=registry, ) + def test_PBES2HS_with_small_p2c(self): + key = OctKey.generate_key(128) + protected = { + "alg": "PBES2-HS256+A128KW", + "enc": "A128CBC-HS256", + "p2s": "QoGrcBpns_cLWCQPEVuA-g", + "p2c": 500, + } + registry = JWERegistry(algorithms=["PBES2-HS256+A128KW", "A128CBC-HS256"]) + self.assertWarns( + SecurityWarning, + encrypt_compact, + protected, + b"i", + key, + registry=registry, + ) + + def test_PBES2HS_with_large_p2c(self): + key = OctKey.import_key({"k": "pyL42ncDFSYnenl-GiZjRw", "kty": "oct"}) + protected = { + "alg": "PBES2-HS256+A128KW", + "enc": "A128CBC-HS256", + "p2s": "QoGrcBpns_cLWCQPEVuA-g", + "p2c": 500000, + } + registry = JWERegistry(algorithms=["PBES2-HS256+A128KW", "A128CBC-HS256"]) + self.assertRaises( + InvalidHeaderValueError, + encrypt_compact, + protected, + b"i", + key, + registry=registry, + ) + encrypted = "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwicDJzIjoiUW9HcmNCcG5zX2NMV0NRUEVWdUEtZyIsInAyYyI6NTAwMDAwfQ.qdtshVQlPM-fW57DRVUnmwMyvBVzUZCm58zn7j5W7IP9S2-cBVTh_w.mMUagTUTRi7fLQ3VUi6g4w.Hi0-8_MusxEwRtW6dkjXzw.Ktm1FmBA9rPe0Vv8w0kZ2g" + self.assertRaises( + InvalidHeaderValueError, + decrypt_compact, + encrypted, + key, + registry=registry, + ) + def test_with_zip_header(self): private_key: RSAKey = load_key("rsa-openssl-private.pem") public_key: RSAKey = load_key("rsa-openssl-public.pem")
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-w5r5-m38g-f9f9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-27932ghsaADVISORY
- github.com/authlib/joserfc/commit/696a961ghsaWEB
- github.com/authlib/joserfc/commit/696a9611ab982c45ee2190ed79ca8e1d8e09398fghsax_refsource_MISCWEB
- github.com/authlib/joserfc/security/advisories/GHSA-w5r5-m38g-f9f9ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.