Skip to content

JWT attacks

A JWT carries signed claims between parties; it’s heavily used for sessions and API authorization. Flaws appear when signature verification is weak or incorrect: the attacker then forges or tampers the token and becomes another user or an admin.

Identity forgery (change sub/user), privilege escalation (set role: admin), authentication bypass, and persistence if tokens don’t expire or aren’t revoked.

Three Base64URL parts separated by dots: header.payload.signature.

  • header: algorithm (alg) and sometimes kid, jku, x5u, jwk.
  • payload: claims (sub, role, exp, iss, aud…).
  • signature: HMAC (HS256) or asymmetric signature (RS256/ES256). Security depends entirely on correctly verifying the signature and the expected alg.

Find JWTs (cookies, Authorization: Bearer, bodies), decode header and payload (Base64URL) and identify alg, kid, jku and the claims that decide access.

# 1) alg=none (app accepts unsigned tokens)
header: {"alg":"none","typ":"JWT"} -> altered payload -> empty signature
# 2) HS/RS confusion (RS256 -> HS256)
# If it verifies HS256 using the PUBLIC KEY as the HMAC secret:
# sign the token with the RSA public key (which is public) as the HS256 secret.
# 3) Weak HMAC secret (HS256) -> crack offline
hashcat -m 16500 token.jwt wordlist.txt # 16500 = JWT
# secret cracked -> sign arbitrary tokens
# 4) kid injection
# kid -> path traversal (point to /dev/null or a known file) or SQLi
# 5) jku / x5u -> SSRF to your JWKS
# point jku at your server with your public key -> sign with your private key
# 6) jwk header injection
# embed your own public key in the header and sign with your private key

Always check whether the app verifies the signature (alter a claim without touching the signature; if you get through, it doesn’t verify) and whether it honors exp.

jwt_tool (automates all of these), hashcat (HMAC secret), jwt.io (decode/inspect).

ATO, admin access, access to other users’ APIs (combined with IDOR), persistence.

  • Tokens with alg: none, unexpected alg, or jku/x5u pointing to external domains.
  • Spikes of verification errors; tokens with exp in the past being accepted.

Verifier/IdP logs, WAF/API gateway, and token-validation metrics.

  1. Always verify the signature and pin the expected algorithm (allow-list; don’t let the token choose). Reject none.
  2. Strong HMAC secret (random, long) or well-managed asymmetric keys.
  3. Validate iss, aud, exp, nbf; don’t trust kid/jku/x5u without an origin allow-list.
  4. Short expiry + revocable refresh tokens; don’t store secrets in the payload (it’s signed, not encrypted: it’s readable).

Rotate the signing key/secret (invalidates all tokens), review access, and fix the verification.

  • alg:none / algorithm-confusion vulnerability — numerous JWT libraries (across languages) suffered it around 2015 and it has resurfaced in later implementations; it’s JWT’s historic flaw.
  • Weak default HMAC secrets in apps/templates → forgery after cracking.

Per-library CVEs in NVD (https://nvd.nist.gov/vuln/search) and GitHub Advisories (https://github.com/advisories).

  • Is the signature verified? (alter a claim without touching the signature).
  • alg:none and HS/RS confusion tested.
  • HS256 secret cracking attempted (hashcat).
  • kid, jku, x5u, jwk tested (injection/SSRF).
  • exp/iss/aud validation checked.