-
Notifications
You must be signed in to change notification settings - Fork 261
Description
Security Advisory
Reported by: Conner Webber (conner.webber000@gmail.com)
Note: Private vulnerability reporting (PVRA) is disabled on this repo and no SECURITY.md exists, so filing here. These findings extend beyond CVE-2024-33663 (OpenSSH ECDSA algorithm confusion).
Finding 1: Algorithm Confusion via DER-Encoded Keys (CRITICAL, CWE-327)
Files: jose/backends/cryptography_backend.py:543, jose/backends/native.py:39
CVE-2024-33663 fixed algorithm confusion for OpenSSH ECDSA keys, but DER-encoded RSA public keys remain undetected. The HMAC key constructor checks if is_pem_format(key) or is_ssh_key(key) but does NOT detect DER-encoded keys. An attacker can:
- Obtain the server's RSA public key in DER format (or convert PEM→DER)
- Sign a forged JWT with HS256 using the raw DER bytes as the HMAC secret
- If the server calls
jwt.decode(token, public_key_der)without specifyingalgorithms, the token validates
This bypasses the existing OpenSSH key format check added for CVE-2024-33663.
Finding 2: Default algorithms=None Still Skips Whitelist (HIGH, CWE-757)
Files: jose/jwt.py:66, jose/jws.py:258
Related to CVE-2024-33663 but still unfixed: jwt.decode() defaults algorithms=None. When None, the algorithm whitelist check at jws.py:258 is skipped entirely, allowing attacker-controlled algorithm selection from the JWT header. PyJWT made algorithms required after CVE-2022-29217 — python-jose has not.
Finding 3: Empty HMAC Key Accepted (HIGH, CWE-326)
Files: jose/backends/cryptography_backend.py:527, jose/backends/native.py:23
Both HMAC backends accept empty string ("") or empty bytes (b"") as valid signing keys. An empty HMAC key produces deterministic signatures that anyone can forge. No validation rejects zero-length keys.
import jose.jwt as jwt
# This succeeds — should raise an error
token = jwt.encode({"admin": True}, "", algorithm="HS256")
jwt.decode(token, "", algorithms=["HS256"]) # ValidFinding 4: Non-Constant-Time JWE Auth Tag Comparison (MEDIUM, CWE-208)
File: jose/jwe.py:247
JWE authentication tag verification uses Python != operator instead of hmac.compare_digest(), enabling timing side-channel attacks to forge valid auth tags byte-by-byte.
Finding 5: Non-Constant-Time at_hash Comparison (MEDIUM, CWE-208)
File: jose/jwt.py:471
OpenID Connect at_hash claim verification uses Python != instead of constant-time comparison, enabling timing attacks.
Impact
- Finding 1+2: Full authentication bypass — attacker with the RSA public key (often publicly available) can forge arbitrary JWT tokens
- Finding 3: Token forgery if any code path uses an empty key
- Finding 4+5: Timing oracle for JWE tag and OIDC at_hash forgery
Recommended Fixes
- Add DER format detection to HMAC key validation (check for ASN.1 SEQUENCE header
0x30) - Make
algorithmsa required parameter injwt.decode()(breaking change, but PyJWT did this) - Reject empty HMAC keys with
ValueError - Replace
!=withhmac.compare_digest()injwe.py:247andjwt.py:471
References
- CVE-2024-33663 — Original algorithm confusion (OpenSSH ECDSA keys)
- CVE-2022-29217 — Equivalent issue in PyJWT (fixed by requiring
algorithmsparam) - Algorithm confusion with OpenSSH ECDSA keys and other key formats #346, algorithm confusion issue #367 — Related existing issues on this repo