CVE-2026-102274: Malformed RSA JWK Aborts PyJWT JWK Set Parsing
SecDim Security Research reported CVE-2026-102274 to the PyJWT maintainer on 2026-09-05, and the vulnerability was subsequently fixed in PyJWT 2.14.0. A single malformed RSA key inside a JWK Set can abort parsing of the entire set. The exception stops parsing before any subsequent key is processed, including keys unrelated to the malformed entry.
The vulnerability
PyJWT’s PyJWKSet class provides the constructor that builds a JWK Set from a list of keys. It is designed to skip unusable keys and continue processing the rest of the set. Each key’s construction is wrapped in error handling that catches PyJWT’s own exception base class, PyJWTError, and skips forward on failure:
for key in keys:
try:
self.keys.append(PyJWK(key))
except PyJWTError as error:
if isinstance(error, MissingCryptographyError):
raise error
# skip unusable keys
continue
That design only holds if every failure inside the loop actually raises a PyJWTError.
The initializer for an individual key, PyJWK, calls directly into the matching algorithm’s key-construction logic, with no exception handling of its own. For an RSA key, that logic is the RSA algorithm’s from_jwk function, responsible for reconstructing a usable key object from the fields present in the JWK.
Some RSA private JWKs include a set of precomputed values that let from_jwk reconstruct the key efficiently. When those values are absent, it instead has to recover the key’s prime factors from the public modulus and the private exponent, using a function from the underlying cryptography library.
The recovery only succeeds if the supplied private exponent is actually valid for the given modulus and public exponent. If it is not, cryptography cannot factor the modulus and raises a ValueError, a generic Python exception rather than one of PyJWT’s own types. Because ValueError is not a subclass of PyJWTError, the guard shown above does not catch it. The exception propagates straight out of the constructor and terminates the loop before any subsequent key gets processed.
Proof of concept
A JWK Set is constructed with two keys: one deliberately malformed, one valid. Only the malformed key should be skipped. Instead, neither key is added to the resulting set.
import jwt
good_jwk = {
"kty": "RSA",
"n": "<a valid base64url-encoded RSA modulus>",
"e": "AQAB",
}
bad_jwk = {
"kty": "RSA",
"n": good_jwk["n"],
"e": "AQAB",
"d": "AAAAAA", # not a valid private exponent for this modulus
}
jwt.PyJWKSet.from_dict({"keys": [bad_jwk, good_jwk]})
# raises: ValueError: Unable to compute factors p and q from exponent d.
# (uncaught, good_jwk is never added)
Impact
Exploitation requires a malformed key to be present in a JWK Set that the target application parses.
In a multi-tenant platform that lets each tenant register its own signing key, or a gateway that combines JWKS from several upstream identity providers into a single document, a single malformed key can be used to abort parsing of the entire set.
An adversary can register their own tenant’s signing key to inject a malformed key into the shared JWK Set, causing parsing to fail and disrupting token verification for all tenants relying on that set.
Every key in the affected set becomes unusable at once, so every legitimate token relying on any of those keys fails to validate until the malformed entry is removed or the library is patched.
Advisory timeline
- 2026-09-05: SecDim Security Research reports the vulnerability to the PyJWT maintainer. Day 0 of a 90-day responsible disclosure window.
- 2026-09-08: The maintainer reproduces the issue on PyJWT 2.13.0 and confirms the independently verified affected range,
>= 2.9.0through<= 2.13.0. A narrow fix is prepared; the advisory is published. - 2026-09-10: The fix lands on
master(commit8915570). The full test suite, linting, and type checks pass. - 2026-09-11: PyJWT 2.14.0 is released with the fix.
- 2026-12-04: Scheduled full-disclosure deadline (Day 90), extendable by 14 days if a tagged release is imminent but not yet shipped.
Fix status
The fix shipped in PyJWT 2.14.0. PyJWK now converts key-construction ValueErrors into InvalidKeyError, a PyJWTError subclass. This allows the constructor’s existing skip logic to function as originally intended. Users running an affected version should upgrade to PyJWT 2.14.0 or later.
References
- CVE: CVE-2026-102274
- Advisory: Malformed RSA JWK aborts parsing of an entire JWK Set · Advisory · jpadilla/pyjwt · GitHub
- CVSS 5.9, medium severity
- CWE-755, Improper Handling of Exceptional Conditions
- Affected: PyJWT
>= 2.9.0through<= 2.13.0(independently verified; earlier releases not checked)
Find, hack and fix this vulnerability in: jwt.py sandbox
