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

CVE-2026-102270: PyJWT PEM Parser DOS Vulnerability

CVE-2026-102270 is a denial of service flaw in PyJWT that allows attackers to cause intensive CPU consumption through malformed PEM inputs. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-102270 Overview

CVE-2026-102270 is a regular expression denial of service (ReDoS) vulnerability in PyJWT, a widely used Python implementation of the JSON Web Token (JWT) standards. Versions prior to 2.14.0 contain a lazy PEM regular expression in the is_pem_format helper that backtracks extensively when parsing certificate-like input. An attacker who supplies a payload containing repeated BEGIN markers without a matching END marker can trigger unbounded backtracking. The result is intensive CPU consumption in the process performing the PEM detection. The issue is tracked under [CWE-1333: Inefficient Regular Expression Complexity] and is fixed in PyJWT 2.14.0.

Critical Impact

An authenticated attacker able to submit crafted key material to a PyJWT consumer can exhaust CPU resources and degrade or halt availability of the affected service.

Affected Products

  • PyJWT versions prior to 2.14.0
  • Python applications that pass attacker-influenced key material to jwt.utils.is_pem_format
  • Downstream libraries and services bundling vulnerable PyJWT releases

Discovery Timeline

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

Technical Details for CVE-2026-102270

Vulnerability Analysis

The defect resides in jwt/utils.py, where is_pem_format uses a regular expression to determine whether a byte string looks like a PEM-encoded key. The original pattern matched a BEGIN marker, then lazily consumed content up to a corresponding END marker of the same label. When input contains many BEGIN markers but no matching END, the regex engine repeatedly retries alternative match positions before failing. This is a textbook algorithmic complexity attack against a backtracking regex engine. Because is_pem_format runs during key parsing, any code path that feeds attacker-controlled key data into PyJWT can be forced into a long CPU-bound loop, blocking the thread and starving other requests.

Root Cause

The root cause is an unbounded lazy quantifier (.+?) combined with a required tail (----[- ]END \1[- ]----) inside a re.DOTALL pattern. When the tail cannot be satisfied, the engine backtracks across every possible split of the lazy region for every BEGIN prefix, producing worst-case behavior consistent with [CWE-1333].

Attack Vector

Exploitation requires the attacker to control the byte string passed to is_pem_format. In practice this occurs when applications accept public keys, certificates, or JWKS material from users, tenants, or federated identity providers and then attempt to load them through PyJWT. Submitting a payload of repeated -----BEGIN CERTIFICATE----- markers without a closing -----END----- triggers the pathological match.

python
# Patch from PyJWT 2.14.0 — jwt/utils.py
# Replaces the backtracking regex with a non-consuming lookahead that
# enumerates BEGIN/END markers and validates pairing in linear time.

-_PEM_RE = re.compile(
-    b"----[- ]BEGIN ("
-    + b"|".join(_PEMS)
-    + b""")[- ]----\r?
-.+?\r?
-----[- ]END \\1[- ]----\r?\n?""",
-    re.DOTALL,
+_PEM_MARKER_RE = re.compile(
+    b"(?=(----[- ](BEGIN|END) (" + b"|".join(_PEMS) + b")[- ]----))"
 )


def is_pem_format(key: bytes) -> bool:
-    return bool(_PEM_RE.search(key))
+    begin_markers: dict[bytes, int] = {}
+    for marker in _PEM_MARKER_RE.finditer(key):
+        marker_type, label = marker.group(2), marker.group(3)
+        if marker_type == b"BEGIN":
+            begin_markers[label] = marker.start(1) + len(marker.group(1))
+        elif label in begin_markers and begin_markers[label] < marker.start(1):
+            return True
+    return False

Source: PyJWT commit 8b4e233

Detection Methods for CVE-2026-102270

Indicators of Compromise

  • Sustained single-thread CPU saturation in Python processes that call jwt.utils.is_pem_format or jwt.algorithms.*.from_jwk.
  • Request payloads or JWKS documents containing many repeated -----BEGIN markers without a matching -----END line.
  • Application timeouts, worker restarts, or 5xx spikes correlated with authentication or token-verification endpoints.

Detection Strategies

  • Inventory Python dependencies and flag any PyJWT version below 2.14.0 using pip list, SBOM tooling, or software composition analysis.
  • Add application-layer logging around PEM/JWK ingestion paths to record input size, marker counts, and parse duration.
  • Alert on anomalous CPU time per request on token verification endpoints, especially where request bodies contain certificate-like material.

Monitoring Recommendations

  • Track process CPU utilization and event loop lag for services that handle JWTs from untrusted sources.
  • Monitor web application firewall (WAF) logs for POST bodies containing repeated BEGIN markers.
  • Correlate authentication error rates with upstream identity provider changes that may introduce new key material.

How to Mitigate CVE-2026-102270

Immediate Actions Required

  • Upgrade PyJWT to 2.14.0 or later in all Python environments, including containers, serverless functions, and CI runners.
  • Rebuild and redeploy application images to ensure transitive PyJWT dependencies are refreshed.
  • Enforce strict size limits on any user-supplied key or certificate material before it reaches PyJWT.

Patch Information

The fix is available in the PyJWT 2.14.0 release. Technical details are documented in GitHub Security Advisory GHSA-jwrc-g2q2-pq5p and the upstream commit. The patch replaces the backtracking regex with a lookahead-based marker scan and validates BEGIN/END pairing in linear time.

Workarounds

  • Reject inputs to key-parsing routines that exceed a conservative byte length (for example, 16 KB) before invoking PyJWT.
  • Wrap calls into PyJWT key loaders with a CPU or wall-clock timeout using a worker process or signal.alarm on POSIX systems.
  • Filter incoming payloads at the WAF or API gateway to drop requests containing more than one -----BEGIN marker in unexpected fields.
bash
# Upgrade PyJWT to the fixed release
pip install --upgrade "PyJWT>=2.14.0"

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

# Audit environments for vulnerable versions
pip list --format=freeze | grep -i '^PyJWT=='

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.