CVE-2026-102268 Overview
CVE-2026-102268 is a key confusion vulnerability in PyJWT, the Python implementation of the JSON Web Token (JWT) standard. Versions prior to 2.14.0 contain a flaw in the is_pem_format function in jwt/utils.py, which fails to recognize every PEM representation accepted by the underlying cryptography loader. Applications that mix HMAC and asymmetric algorithms can be tricked into treating a mutated public-key PEM as an HMAC secret. An attacker who knows the public key can then forge authenticated HMAC tokens accepted by the verifier. The issue is fixed in PyJWT 2.14.0 and is classified under [CWE-347: Improper Verification of Cryptographic Signature].
Critical Impact
Attackers with knowledge of a service's public key can forge valid JWTs, bypassing authentication and impersonating any user or service.
Affected Products
- PyJWT versions prior to 2.14.0
- Python applications using PyJWT that accept both HMAC and asymmetric algorithms
- Services passing raw PEM bytes as candidate keys to HMACAlgorithm.prepare_key
Discovery Timeline
- 2026-09-28 - CVE-2026-102268 published to NVD
- 2026-09-30 - Last updated in NVD database
Technical Details for CVE-2026-102268
Vulnerability Analysis
PyJWT distinguishes HMAC secrets from asymmetric keys by inspecting whether a supplied key looks like a PEM-encoded structure. The is_pem_format helper in jwt/utils.py uses a regular expression to detect PEM markers. However, its regex is stricter than the PEM parser used by the cryptography library. Certain valid PEM variants pass the cryptography loader but are rejected by is_pem_format.
When an application mixes algorithms and passes raw key bytes, HMACAlgorithm.prepare_key interprets the unrecognized asymmetric public key as a symmetric HMAC secret. An attacker who can influence the alg header (for example, switching from RS256 to HS256) can then sign a token using the target's known public key, and the verifier accepts it as authentic.
Root Cause
The original _PEM_RE regular expression required a strict -----BEGIN X-----...-----END X----- structure with specific separator characters. The cryptography library accepts additional PEM variants that this regex misses, causing is_pem_format to return False for keys that are, in fact, valid asymmetric PEMs. This mismatch enables the algorithm confusion path.
Attack Vector
Exploitation requires network access to a JWT-consuming endpoint and knowledge of the target's public key, which is often published (for example via JWKS endpoints). The attacker crafts a JWT with alg: HS256, signs it with the public key bytes as the HMAC secret, and sends it. No privileges or user interaction are required.
b"X509 CRL",
}
-_PEM_RE = re.compile(
- b"----[- ]BEGIN ("
- + b"|".join(_PEMS)
- + b""")[- ]----\r?
-.+?\r?
-----[- ]END \\1[- ]----\r?\n?""",
- re.DOTALL,
+# Accept PEM formatting variants that the cryptography loader accepts, while
+# retaining the explicit asymmetric-key marker check.
+_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: GitHub Commit for PyJWT. The patch replaces the strict PEM regex with a marker-based scan that mirrors the acceptance criteria of the cryptography PEM loader, closing the classification gap.
Detection Methods for CVE-2026-102268
Indicators of Compromise
- JWTs presented to the application with alg: HS256 (or other HMAC variants) when the service normally issues asymmetric tokens such as RS256 or ES256.
- Successful authentications where the token signature was verified using bytes that match a known public key.
- Unexpected access to protected endpoints from accounts whose credentials show no corresponding successful login.
Detection Strategies
- Inventory Python dependencies and flag any deployment using PyJWT below 2.14.0.
- Instrument JWT verification code paths to log the alg header and reject algorithm values inconsistent with the issuer's key material.
- Correlate JWT-based authentications with upstream identity provider events to spot tokens with no matching issuance record.
Monitoring Recommendations
- Ingest application authentication logs into a centralized analytics pipeline and alert on sudden shifts in JWT alg distribution.
- Monitor access to JWKS and public-key endpoints for unusual scraping activity that may precede forgery attempts.
- Track anomalous session creation from new IP addresses paired with privileged JWT claims.
How to Mitigate CVE-2026-102268
Immediate Actions Required
- Upgrade PyJWT to version 2.14.0 or later across all applications and container images.
- Audit application code to ensure jwt.decode calls pass an explicit algorithms= allowlist scoped to the expected asymmetric algorithm.
- Rotate any signing keys or shared secrets that may have been exposed to untrusted parties since deployment.
Patch Information
The fix is committed in GitHub Commit 8b4e233 and shipped in the PyJWT 2.14.0 release. Full technical context is available in GitHub Security Advisory GHSA-ffc3-869f-jxw9.
Workarounds
- Restrict accepted algorithms in every jwt.decode call by passing an algorithms parameter that contains only asymmetric algorithms such as ["RS256"].
- Do not share verification keys between HMAC and asymmetric code paths; keep symmetric secrets and public keys in separate key stores.
- Reject any inbound JWT whose alg header does not match the algorithm expected for the issuer.
# Upgrade PyJWT to the fixed release
pip install --upgrade "pyjwt>=2.14.0"
# Verify the 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.