CVE-2026-101918: PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)
PyJWKClient.get_signing_key_from_jwt(token) — the first step of the JWKS
verification flow documented in docs/usage.rst — must decode a token’s
payload before its signature can be checked, via
jwt.api_jwt.decode_complete(token, options={"verify_signature": False}).
That call parses the payload with json.loads in PyJWT._decode_payload
(jwt/api_jwt.py:297-300), whose except clause catches only ValueError.
A payload that is valid JSON but nested ~20,000 levels deep makes
json.loads raise RecursionError, which is not a ValueError and
escapes as a raw, undocumented exception type — not DecodeError,
InvalidTokenError, or PyJWTError, so every documented error-handling
pattern in docs/usage.rst misses it.
The token needs no valid signature and no network access — the crash
happens during payload parsing, before the kid is even looked up. A
single unauthenticated ~50KB request crashes the caller’s auth handler
(HTTP 500 / dead worker), repeatably. The same path is reachable through
plain jwt.decode(token, options={"verify_signature": False}) too.
Notably, this project already fixed the identical bug class for the
JWS header path — PyJWS._load catches (ValueError, RecursionError)
and wraps it in DecodeError (jwt/api_jws.py:360-361), and
CHANGELOG.rst (v2.14.0, “Security”) states “Handle deeply nested and
malformed JWS/JWK input without uncaught recursion errors.” The payload
path — the one part of a forged token an unauthenticated attacker fully
controls — was left catching ValueError alone, so that security fix does
not fully hold.
A second, related instance: PyJWKClient.fetch_data (jwt/jwks_client.py:168)
parses a JWKS endpoint’s response with json.load(response) inside a
try that only catches (URLError, TimeoutError, http.client.HTTPException)
— a deeply-nested JSON response from a JWKS endpoint raises the same raw
RecursionError, uncaught entirely (worse than the payload path, which at
least caught plain ValueError).
Affected versions: confirmed present in the current release, 2.14.0,
and on the current master branch (commit 4adcd02722f5011c60079d3978dfc167b9a8eaa5).
References
Code Behaviors & Features
Detect and mitigate CVE-2026-101918 with GitLab Dependency Scanning
Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Learn more about Dependency Scanning →