chore(deps): update dependency joserfc to v1.6.8 [security] - autoclosed #35
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "renovate/pypi-joserfc-vulnerability"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This PR contains the following updates:
1.6.7→1.6.8joserfc: HS256/HS384/HS512 verify accepts empty/nil HMAC key (cross-language sibling of CVE-2026-45363)
CVE-2026-49852 / GHSA-gg9x-qcx2-xmrh
More information
Details
Summary
joserfc.jwt.decodeaccepts attacker-forged HMAC-signed tokens when thecaller-supplied verification key is the empty string or
None.HMACAlgorithm.signandHMACAlgorithm.verifyinsrc/joserfc/_rfc7518/jws_algs.py:62-70feed whateverOctKey.get_op_key(...)produced intohmac.new(...), andOctKey.import_keyonly emits a
SecurityWarningwhen the raw key is shorter than 14 byteswithout rejecting zero-length input. Any application whose JWT secret is
sourced from an unset environment variable, an unset Redis / DB row, a key
finder fallback that returns
"", or aHash.new("")-style default verifiesattacker tokens forged with
HMAC(key=b"", signing_input)because theattacker trivially reproduces the same digest with no secret knowledge.
This is a cross-language sibling of jwt/ruby-jwt GHSA-c32j-vqhx-rx3x /
CVE-2026-45363 (HS256/HS384/HS512 verify accepted an empty/nil HMAC key,
filed 2026-05-13). ruby-jwt v3.2.0 added an
ensure_valid_key!preconditionthat rejects empty keys at both sign and verify entry; joserfc has no
equivalent. (The same primitive lives in the deprecated
authlib.josemodule by the same maintainer; filing this advisory against joserfc
alongside a separate
authlibadvisory because the codebases areindependent shipping artifacts on PyPI.)
Affected versions
joserfc(PyPI)<= 1.6.7(latest published release reproduces). Nopatched release.
Privilege required
Unauthenticated. Any HTTP / RPC endpoint that calls
joserfc.jwt.decodewith a verification key sourced from configuration is reachable. The
condition that makes the bug observable is operator-side: the configured
secret resolves to
""orNone. Common patterns that produce this statein production:
OctKey.import_key(os.environ.get("JWT_SECRET", ""))""/Nonefor an unknownkidos.getenv("SECRET") or "",cfg.get("secret", "")""for a missing rowVulnerable code
src/joserfc/_rfc7518/jws_algs.py:43-70:src/joserfc/_rfc7518/oct_key.py:52-63:The
< 14check only warns;len(key.raw_value) == 0falls through and isreturned to the caller.
HMACAlgorithm.verifythen callshmac.compare_digest(sig, hmac.new(b"", signing_input, sha256).digest()),and Python's
hmac.new(b"", ...)accepts the empty key.Cross-language sibling of ruby-jwt's fix in
lib/jwt/jwa/hmac.rb:invoked from both
sign(signing_key:)andverify(verification_key:).PyJWT landed an equivalent guard in 2.13.0 (
HMACAlgorithm.prepare_keyraises
InvalidKeyError("HMAC key must not be empty.")forlen(key_bytes) == 0).firebase/php-jwt rejects empty material in
Key.__construct. jjwt enforces a256-bit minimum in
DefaultMacAlgorithm.validateKey. joserfc has thestrongest existing length-warning logic but stops at
< 14 byteswarnrather than
== 0reject.How an empty
JWT_SECRETreacheshmac.newjoserfc.jwt.decode(value, key, algorithms=["HS256"])where
key = OctKey.import_key("")(orOctKey.import_key(b""),or any custom path that yields an
OctKeywhoseraw_valueisb"").decode(src/joserfc/jwt.py:86-117) calls_decode_jws(...)→deserialize_compact(value, key, algorithms, registry).deserialize_compact(src/joserfc/jws.py) dispatches toHMACAlgorithm.verify(signing_input, signature, key).verifycallskey.get_op_key("verify")→ returnsb"".hmac.new(b"", signing_input, sha256).digest()is computed; theattacker computed exactly that digest with the same empty key, so
hmac.compare_digestreturnsTrueand decode succeeds.No upstream
nil-check, no length check, no schema rejection. The path isreached from the public
joserfc.jwt.decodeAPI.Proof of concept
Attacker (no secret knowledge):
Server harness:
End-to-end reproduction (against
pip install joserfc==1.6.7)Captured run output (canonical pre-fix run, joserfc 1.6.7,
poc-attacker-empty-20260523-150949.log):Control (real 256-bit secret,
poc-control-realkey-20260523-150959.log):Interpretation:
JWT_SECRETunset (== "")admin=True(verified)JWT_SECRET= 256-bit valueBadSignatureErrorThe first row demonstrates that an attacker with zero knowledge of the
verification secret reaches the protected path by signing with the empty
key. The second row confirms the verifier behaves correctly when the
secret is non-empty, proving the bug is gated only on the secret being
empty rather than on any structural defect in the attacker's token.
Fix verification: with the suggested empty-key reject wired into
HMACAlgorithm.sign/.verify, the empty-secret server re-run rejectsthe same forged token with
ValueError: HMAC key must not be empty.Impact
to
""/None(env var unset, DB row missing, fallback). Attackerforges arbitrary claims (
sub,admin, scopes, audience, expiry).not fail to boot, joserfc emits a single
SecurityWarning("Key sizeshould be >= 112 bits") at
OctKey.import_keytime and then proceeds.CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N — AC:H because of the
operator-misconfiguration precondition; impact otherwise matches
authentication bypass.
Suggested fix
Upgrade the existing
< 14 byteswarning inOctKey.import_keyto a hardreject at
len(key.raw_value) == 0, plus a defence-in-depth check inHMACAlgorithm.signandHMACAlgorithm.verifyafterkey.get_op_key(...):The two-layer fix mirrors PyJWT 2.13.0's approach (reject empty in
prepare_key, plus the runtime length checks the underlying hmacprimitive does not perform).
Fix PR
authlib/joserfc-ghsa-gg9x-qcx2-xmrh#1(temp private fork PR), branchfix/hmac-reject-empty-key, basemain. URL:https://github.com/authlib/joserfc-ghsa-gg9x-qcx2-xmrh/pull/1
Credit
Reported by tonghuaroot.
Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
authlib/joserfc (joserfc)
v1.6.8Compare Source
Full Changelog: https://github.com/authlib/joserfc/compare/1.6.7...1.6.8
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Mend Renovate.
chore(deps): update dependency joserfc to v1.6.8 [security]to chore(deps): update dependency joserfc to v1.6.8 [security] - autoclosedPull request closed