Repository navigation
2.13.0 #1172
jpadilla
announced in
Announcements
2.13.0
#1172
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
PyJWT 2.13.0 — Security Release
This release bundles five security fixes plus three additional hardening / spec-compliance changes. We recommend all users upgrade.
Security
GHSA-xgmm-8j9v-c9wx— JWK JSON accepted as HMAC secret (algorithm confusion).HMACAlgorithm.prepare_keypreviously rejected PEM- and SSH-formatted asymmetric keys but did not catch a JWK passed as a raw JSON string. In a verifier configured with both symmetric and asymmetric algorithms inalgorithms=[…]and a raw-JSON JWK as the key, an attacker could forge HS256 tokens using the JWK text as the HMAC secret. The guard has been extended to reject any JWK-shaped JSON. Reported by @aradona91.GHSA-jq35-7prp-9v3f— Algorithm allow-list bypass withPyJWK/PyJWKClient. When verifying with aPyJWK, the caller'salgorithms=[…]allow-list was checked against the token headeralgas a string only; actual verification used the algorithm bound to thePyJWK. An attacker who controlled a registered JWKS key could sign with one algorithm and advertise another on the header. PyJWT now requires the token headeralgto match thePyJWK's algorithm before verification. Reported by @sushi-gif.GHSA-w7vc-732c-9m39— DoS via base64 decode of unused payload segment whenb64=false. For detached-payload JWS (b64=false), the compact-form payload segment was base64-decoded before being discarded in favor of the caller-supplieddetached_payload. An attacker could inflate the unused segment to force CPU + memory cost without holding a valid signature. The segment is now required to be empty per RFC 7515 Appendix F, and is no longer decoded. Reported by @thesmartshadow.GHSA-993g-76c3-p5m4—PyJWKClientaccepts non-HTTP(S) URIs.PyJWKClient.fetch_datapassed its URI tourllib.request.urlopen, which by default also handlesfile://,ftp://, anddata:schemes. An application that fed an attacker-influenced URI intoPyJWKClientcould be coerced into reading local files or reaching other unintended schemes.PyJWKClientnow rejects any URI whose scheme isn'thttporhttps. Reported by @KEIJOT.GHSA-fhv5-28vv-h8m8—PyJWKClientcache wiped on fetch error. Afinally-blockput(jwk_set=None)cleared the JWK Set cache whenever a fetch raised, turning a transient JWKS-endpoint outage into application-wide auth failure. The cache write was moved into the success path; transient errors no longer evict valid cached keys. Reported by @eddieran.Fixed
HMACAlgorithm.prepare_keywithInvalidKeyErrorinstead of accepting them with only a warning. Defends against theos.getenv("JWT_SECRET", "")footgun. Thanks to @SnailSploit and @spartan8806 for the reports.options(includingenforce_minimum_key_length) fromPyJWT.decodethrough toPyJWS._verify_signature. The option was previously silently dropped between the two layers, so it only took effect when set on thePyJWTinstance. Thanks to @WLUB for the report.b64=false: the encoder now auto-adds"b64"tocrit, and the decoder rejects tokens that setb64=falsewithout listing it incrit. Thanks to @MachineLearning-Nerd for the report.Changed
dev,docs, andtestspackage extras to dependency groups, by @kurtmckee in #1152.Upgrade notes
Most fixes are invisible to correctly-configured callers. A few behavioral changes you may encounter:
""orb""as a secret (often via a missing env var, e.g.os.getenv("JWT_SECRET", "")),encode/decodewill now raiseInvalidKeyError. This is the intended behavior — fix the configuration.PyJWKdecoding now requires the token'salgto match the JWK's algorithm. Previously a mismatch was silently honored if the headeralgappeared in the allow-list. Tokens that relied on this mismatch will now fail withInvalidAlgorithmError.PyJWKClientnow rejects non-HTTP(S) URIs at construction time. Tests or dev environments that fetched JWKS fromfile://URIs need to switch to a local HTTP server or load the JWKS by other means (e.g. constructPyJWKSet.from_dict(...)directly).b64=falsetokens are now strictly RFC 7515 / 7797 compliant. Tokens with a non-empty compact-form payload segment, or that omit"b64"fromcrit, will be rejected. PyJWT-produced tokens always satisfy both invariants, so round-trips through PyJWT are unaffected.enforce_minimum_key_lengthset per-call now takes effect. Callers who passedoptions={"enforce_minimum_key_length": True}tojwt.decode()previously got no enforcement; they will now getInvalidKeyErroron undersized keys, as documented.Full changelog: 2.12.1...2.13.0
This discussion was created from the release 2.13.0.
All reactions