Disclosure summary
### Summary PyJWT accepts internally inconsistent OKP private JWKs where the declared public key `x` does not correspond to the supplied private key `d`. When `d` is present, `OKPAlgorithm.from_jwk()` constructs the Ed25519/Ed448 private key from `d` without verifying that the public key derived from `d` matches `x`. As a result, the original JWK can contain one public key identity while PyJWT performs cryptographic operations using a different key. In affected DPoP integrations, this can allow a stolen sender-constrained access token to be used without possession of the legitimate holder's private key. ### Details The vulnerable logic is in `jwt/algorithms.py`: ```python if "x" not in obj: raise InvalidKeyError('OKP should have "x" parameter') x = base64url_decode(obj.get("x")) if "d" not in obj: if curve == "Ed25519": return Ed25519PublicKey.from_public_bytes(x) return Ed448PublicKey.from_public_bytes(x) d = base64url_decode(obj.get("d")) if curve == "Ed25519": return Ed25519PrivateKey.from_private_bytes(d) return Ed448PrivateKey.from_private_bytes(d) ``` When `d` is present, `x` is parsed but never compared with the public key derived from `d`. For example, PyJWT accepts: ```jso
Source-specific records & product guidance
Sources retain their own attribution and scoring. Follow the original record to confirm affected versions, fixed releases, and configuration conditions.
GitHub Reviewed Security Advisories · GHSA-x33g-cr3x-6449
Open original source · Updated Oct 05, 2026
PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion
Source severity: MEDIUM / 0
| Ecosystem | Package | Affected range | First patched |
|---|---|---|---|
| pip | PyJWT | >= 2.1.0, | 2.15.0 |
Original records & references
- NIST NVD record
- CVE Program record
- github.com — Reviewed advisory
PUBLISHED 2026-10-05T19:44:03-04:00
MODIFIED 2026-10-05T19:44:05-04:00
INGESTED 2026-10-06T11:45:42-04:00