Do not crash on a JWT with a non-base64url signature (fixes #6101) (#6102)

JWT_REGEX accepts a signature segment of any length and parseJWT only
validates the header/payload, so a value that matches the JWT pattern but
carries a malformed/truncated signature (e.g. 41 base64url characters,
which is length % 4 == 1 and thus impossible base64) reached crackHMAC.
There decodeBase64(signature) let binascii.Error propagate, aborting the
whole run with an unhandled exception during checkJWT().

Guard the signature decode: a signature that is not valid base64url cannot
be an HMAC we could verify, so crackHMAC now treats it as not crackable
(returns None) instead of raising. The other auditJWT findings are
unaffected. Added a regression doctest.

Co-authored-by: chan770 <[email protected]>
This commit is contained in:
Ramachandran Thamarai Semmenian
2026-09-01 10:24:58 +02:00
committed by GitHub
co-authored by chan770
parent 1192d266c8
commit 3b8a8d3d09
+9 -1
View File
@@ -89,6 +89,8 @@ def crackHMAC(token, secrets, limit=None):
's3cr3t'
>>> crackHMAC(token, ["admin", "letmein"]) is None
True
>>> crackHMAC("eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.x", ["secret"]) is None
True
"""
data = parseJWT(token)
@@ -97,7 +99,13 @@ def crackHMAC(token, secrets, limit=None):
fn = HMAC_ALGORITHMS[data["header"]["alg"].upper()]
signingInput = getBytes(data["signingInput"])
target = decodeBase64(data["signature"], binary=True)
try:
target = decodeBase64(data["signature"], binary=True)
except Exception:
# a signature segment that is not valid base64url (e.g. a truncated/malformed token that still
# matches the JWT pattern) cannot be an HMAC we could verify, so it is simply not crackable
return None
for index, secret in enumerate(secrets):
if limit is not None and index >= limit: