Disclosure summary
## Package pyjwt (PyPI) ## Affected versions tested & verified on: 2.13.0. Every version whose `PyJWS._load()` translates only `ValueError` is affected ## Description `PyJWS._looad()` (`jwt/api_jws.py:337`) splits the compact token, base64url decodes the header segment and hands it to `json.loads()` before `_verify_signature()` runs. The parse is wrapped in `except ValueError as e: raise DecodeError(...)`. That is what makes the documented contract sufficient for untrusted input: `except jwt.PyJWTError` (or `InvalidTokenError`) around `jwt.decode(token, key, algorithms=[...])`. CPython's JSON decoder raises `RecursionError` (a `RuntimeError` subclass, not a `ValueError`) once nesting crosses the native stack guard. That exception leaves `_load()`, then `jwt.decode()`, and matches no `PyJWTError` handlerr at all. No key and no valid signature are needed: the header is parsed first, so a single unauthenticated request with an unsigned token suffices. Scope: the recursion threshold is ~65,000 nesting levels; below it the same input yields a clean `DecodeError` (a 346,800-byte flat header is rejected normally, so depth, not size, is the trigger). A token this large cannot ride in an `A
Source-specific records & product guidance
Sources retain their own attribution and scoring. Follow the original record to confirm affected versions, fixed releases, and configuration conditions.
GitHub Reviewed Security Advisories · GHSA-8wjv-2p76-3863
Open original source · Updated Sep 29, 2026
PyJWT: Uncaught RecursionError in jwt.decode() on deeply nested token header
Source severity: MEDIUM / 0
| Ecosystem | Package | Affected range | First patched |
|---|---|---|---|
| pip | pyJWT | >= 2.13.0, < 2.14.0 | 2.14.0 |
Original records & references
- NIST NVD record
- CVE Program record
- github.com — Reviewed advisory
PUBLISHED 2026-09-29T19:43:06-04:00
MODIFIED 2026-09-29T19:43:07-04:00
INGESTED 2026-10-06T11:43:08-04:00