Skip to main content
Vulnerability Database/CVE-2026-101918

CVE-2026-101918: PyJWT JSON Web Token DOS Vulnerability

CVE-2026-101918 is a denial of service flaw in PyJWT that allows attackers to trigger HTTP 500 errors through recursively nested payloads. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-101918 Overview

CVE-2026-101918 affects PyJWT, a widely used Python implementation of the JSON Web Token (JWT) standard. Versions from 2.0.0a1 through 2.14.x fail to catch RecursionError when parsing attacker-controlled JWT payloads through PyJWKClient.get_signing_key_from_jwt. The payload parser catches only ValueError, leaving recursively nested JSON payloads to raise uncaught exceptions inside json.loads. Applications relying on documented PyJWT exception handling propagate the failure, typically producing HTTP 500 responses. The same defect impacts jwt/api_jwt.py when verify_signature=False. The issue is resolved in PyJWT 2.15.0.

Critical Impact

Unauthenticated attackers can trigger uncaught RecursionError exceptions in web services that call PyJWT parsing routines, causing availability degradation through HTTP 500 responses.

Affected Products

  • PyJWT versions 2.0.0a1 through 2.14.x
  • Applications using PyJWKClient.get_signing_key_from_jwt
  • Applications calling jwt/api_jwt.py with verify_signature=False

Discovery Timeline

  • 2026-09-28 - CVE-2026-101918 published to NVD
  • 2026-09-30 - Last updated in NVD database

Technical Details for CVE-2026-101918

Vulnerability Analysis

The vulnerability is an Uncaught Exception flaw [CWE-248] in PyJWT's payload decoding path. When PyJWT decodes a JWT, it calls json.loads on the base64-decoded payload segment. The library wraps this call in a try/except ValueError block and re-raises a DecodeError. However, Python's json.loads raises RecursionError — not ValueError — when it encounters deeply nested JSON structures that exceed the interpreter's recursion limit.

Because RecursionError is a subclass of Exception but not ValueError, the exception escapes PyJWT and propagates to the caller. Web frameworks that trust PyJWT's documented exception surface do not catch it, resulting in HTTP 500 responses. Repeated exploitation degrades service availability without requiring authentication.

Root Cause

The root cause is incomplete exception handling in the payload parser. The except clause enumerates only ValueError, ignoring RecursionError raised by CPython's JSON decoder when parsing pathologically nested arrays or objects such as [[[[...]]]].

Attack Vector

An unauthenticated attacker submits a crafted JWT whose payload segment decodes to deeply nested JSON. Any endpoint that passes the token to PyJWKClient.get_signing_key_from_jwt or decodes with verify_signature=False will invoke json.loads on the malicious payload and raise an uncaught RecursionError.

python
         """
         try:
             payload: dict[str, Any] = json.loads(decoded["payload"])
-        except ValueError as e:
+        except (ValueError, RecursionError) as e:
             raise DecodeError(f"Invalid payload string: {e}") from e
         if not isinstance(payload, dict):
             raise DecodeError("Invalid payload string: must be a json object")

Source: PyJWT patch commit 5fde08a. The fix extends the except tuple to include RecursionError, normalizing it into the documented DecodeError contract.

Detection Methods for CVE-2026-101918

Indicators of Compromise

  • Repeated HTTP 500 responses from endpoints that accept JWT bearer tokens from unauthenticated clients.
  • Application logs containing Python tracebacks referencing RecursionError originating in json/decoder.py or jwt/api_jwt.py.
  • Inbound requests with Authorization: Bearer headers whose decoded payload segments exceed typical JWT sizes or contain long runs of [ or { characters.

Detection Strategies

  • Inspect web server and WSGI/ASGI logs for spikes in 500-class responses correlated with JWT-authenticated routes.
  • Monitor Python application error telemetry for RecursionError frames originating in PyJWT call stacks.
  • Deploy a WAF or reverse proxy rule that decodes JWT payload segments and rejects tokens whose JSON nesting depth exceeds a sane threshold (for example, 32).

Monitoring Recommendations

  • Alert on any occurrence of RecursionError in production Python services that consume JWTs.
  • Track request rates against JWT-validation endpoints and flag sustained bursts from a single source.
  • Correlate elevated 500 rates with User-Agent and IP reputation data to identify probing.

How to Mitigate CVE-2026-101918

Immediate Actions Required

  • Upgrade PyJWT to version 2.15.0 or later across all Python environments and container images.
  • Audit dependency manifests (requirements.txt, pyproject.toml, Pipfile.lock) for pinned PyJWT versions in the affected range.
  • Add a defensive except Exception handler around PyJWT decode calls until patched versions are deployed.

Patch Information

The fix ships in PyJWT 2.15.0. See the PyJWT 2.15.0 release notes and the GitHub Security Advisory GHSA-42vr-xj54-vc7v. The patch extends the payload parser's except clause to catch both ValueError and RecursionError, normalizing failures into DecodeError.

Workarounds

  • Wrap all PyJWT parsing calls in a broad exception handler that maps unexpected errors to HTTP 400 responses.
  • Enforce a maximum JWT length at the reverse proxy or API gateway to reduce exposure to oversized payloads.
  • Reject tokens whose decoded payload exceeds a maximum JSON nesting depth before passing them to PyJWT.
bash
# Upgrade PyJWT to the patched release
pip install --upgrade 'pyjwt>=2.15.0'

# Verify installed version
python -c "import jwt; print(jwt.__version__)"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.