CVE-2026-102272 Overview
CVE-2026-102272 is a signature verification flaw ([CWE-347]) in PyJWT, the Python implementation of JSON Web Token (JWT) standards. Versions from 2.13.0 up to (but not including) 2.14.0 contain a defect in HMACAlgorithm.prepare_key located in jwt/algorithms.py. The raw-JWK detector fails to normalize Unicode byte-order marks before checking for JSON content. When a public JSON Web Key (JWK) is prefixed with a UTF-8 BOM and passed through a mixed-algorithm verification path, the key bypasses asymmetric-key detection and is used as an HMAC secret. An attacker who knows the public key can then forge authenticated tokens.
Critical Impact
Attackers with knowledge of a public JWK can forge valid HMAC-signed JWTs, defeating token authenticity and enabling identity impersonation.
Affected Products
- PyJWT 2.13.0
- PyJWT versions after 2.13.0 and before 2.14.0
- Python applications using PyJWT in mixed-algorithm verification paths
Discovery Timeline
- 2026-09-28 - CVE-2026-102272 published to NVD
- 2026-09-30 - Last updated in NVD database
Technical Details for CVE-2026-102272
Vulnerability Analysis
The defect is a classic algorithm-confusion condition against JWT verification. PyJWT's HMACAlgorithm.prepare_key attempts to distinguish between raw HMAC secrets and structured JWK material by parsing the input as JSON. If parsing succeeds and the object contains a kty field, the key is rejected as unsuitable for HMAC use. This safeguard prevents an attacker-supplied public key from being treated as a symmetric secret.
The check does not account for UTF-8 byte-order marks. When a JWK payload is prefixed with a BOM (\\xef\\xbb\\xbf), json.loads raises a ValueError rather than returning the parsed dictionary. The detector falls through to treat the byte string as an opaque HMAC secret. In deployments that accept multiple algorithms during verification, an attacker who has access to the RSA or ECDSA public key can craft a JWT signed with HMAC-SHA256 using that public key material as the shared secret. PyJWT then verifies the forged token successfully.
Root Cause
The root cause is incomplete input normalization in the JWK detection heuristic. The code path relies on strict JSON parsing to identify structured keys, but does not strip BOM sequences or otherwise sanitize the byte stream before evaluation. This allows a trivially modified public key to bypass the guard.
Attack Vector
Exploitation is network-based and requires no authentication or user interaction, though attack complexity is elevated because the target application must expose a mixed-algorithm verification path and the attacker must possess the corresponding public key. Public keys are, by design, non-secret and frequently published via JWKS endpoints.
# bytes (whose contents are not the secret material).
try:
jwk_obj = json.loads(key_bytes)
+ except RecursionError:
+ try:
+ decoded_key = key_bytes.decode(
+ json.detect_encoding(key_bytes), errors="surrogatepass"
+ )
+ except UnicodeError:
+ decoded_key = ""
+ if decoded_key.lstrip().startswith("{"):
+ raise InvalidKeyError(
+ "The specified key looks like a JWK and should not be "
+ "used directly as an HMAC secret. Load it via "
+ "PyJWK / HMACAlgorithm.from_jwk first."
+ ) from None
+ jwk_obj = None
except ValueError:
jwk_obj = None
if isinstance(jwk_obj, dict) and "kty" in jwk_obj:
Source: PyJWT security patch commit 1807839. The patch decodes the key bytes using json.detect_encoding, which handles BOM-prefixed input, and rejects any payload whose stripped content begins with { — raising InvalidKeyError before the material can be used as an HMAC secret.
Detection Methods for CVE-2026-102272
Indicators of Compromise
- JWTs presented to the application whose header specifies alg: HS256 (or other HMAC variants) when the service is expected to accept only RSA or ECDSA tokens.
- Successful verifications where the HMAC secret material corresponds to a known public key exposed via a JWKS endpoint.
- Application logs showing PyJWT decode calls that accept multiple algorithms including at least one HMAC variant alongside asymmetric algorithms.
Detection Strategies
- Inventory Python dependencies and identify services pinning PyJWT versions 2.13.0 through any release prior to 2.14.0.
- Audit source code for jwt.decode invocations whose algorithms argument mixes HMAC and asymmetric algorithm identifiers.
- Instrument JWT verification middleware to log the alg header value and compare it against the algorithm class expected for the issuer.
Monitoring Recommendations
- Alert on any authenticated request whose token header advertises an HMAC algorithm while the issuer's key set publishes only asymmetric keys.
- Monitor for anomalous verification success paths against tokens presented from previously unseen source addresses or user agents.
- Track dependency drift in CI pipelines so that vulnerable PyJWT ranges are flagged during build.
How to Mitigate CVE-2026-102272
Immediate Actions Required
- Upgrade PyJWT to version 2.14.0 or later in all affected services and rebuild container images that bundle the library.
- Restrict the algorithms argument on every jwt.decode call to a single algorithm family that matches the issuer's key type.
- Rotate any public keys that may have been exposed and used as forged HMAC secrets if compromise is suspected.
Patch Information
The fix is delivered in PyJWT release 2.14.0. The patched code path detects the encoding of the incoming key bytes, strips BOMs, and raises InvalidKeyError when the material resembles a JWK. Full technical details are available in GitHub Security Advisory GHSA-r6x4-923q-g947.
Workarounds
- Explicitly pass only asymmetric algorithm identifiers (for example, algorithms=["RS256"]) to jwt.decode until upgrading is possible.
- Load JWK material through PyJWK or HMACAlgorithm.from_jwk rather than passing raw bytes into prepare_key.
- Validate the alg header at the application layer and reject tokens whose algorithm does not match the expected issuer key type.
# Upgrade PyJWT and pin the fixed version
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.