Skip to content

JWT Attack Cheat Sheet

JWT attack patterns (alg none, confusion, kid, jku, weak secrets) paired with pinned verification code.

How it works

JSON Web Tokens fail in predictable ways, and almost none of them are cryptographic: the failures live in verification logic. Libraries that trust the token's own alg header, key identifiers treated as file paths or URLs, claims decoded but never validated — every major JWT incident is one of these patterns. This reference puts each attack next to the exact verification code that defeats it.

The classics are all here: alg=none acceptance, RS256-to-HS256 confusion (signing with the public key as an HMAC secret), weak HMAC secrets cracked offline, kid path traversal, jku/x5u header injection pointing verification at attacker-hosted keys, missing exp/aud/iss validation, and sensitive data sitting in a payload anyone can read.

The defensive pattern is one sentence: pin everything the token should not choose — algorithm family, key source, audience, issuer — and validate every time claim on every request. The reference includes pinned verification snippets for Node and Python so the fix is copy-paste close.

Authorized testing only. Run these against your own services or with written permission. Pair this page with the ToolPlex JWT decoder: decode the token, read the header, then walk the attack list in order.

Worked example

Audit your own API in order: decode the token, check what the header claims, then test whether the server lets the token choose its own verification rules.

TestForged tokenSignal of weakness
alg=none{"alg":"none"}, empty signatureServer accepts the unsigned token.
Confusionalg HS256 signed with the public keyRS256 token verifies against a symmetric path.
Claim validationexpired token, wrong audienceBoth accepted — claims were never checked.
  1. Decode the token: Read header and payload with the JWT decoder; note alg, kid, jku and claims.
  2. Walk the attack list: alg=none, confusion, kid, jku — in that order, fastest first.
  3. Check the claims: Replay expired and wrong-audience tokens to test validation.
  4. Pin and re-test: Apply pinned verification, then confirm every forgery now returns 401.

A fail-closed verifier rejects all three instantly: explicit algorithm allowlist, keys from a pinned internal map, and exp/aud/iss validated per request. Re-test after the fix — the same forgeries must return 401.

Common errors and edge cases

  • Trusting the alg header. The attacker writes the header; the server must choose the algorithm family. algorithms=None or reading alg from the token is the root of both none and confusion attacks.
  • kid as a path or URL. kid is an identifier, not a location. Resolve it against a fixed server-side key map; anything else invites traversal or SSRF.
  • Decoding without verifying. jwt.decode in many libraries skips verification entirely. Verify first, read claims second, on every request including internal ones.
  • Secrets that fit in a wordlist. HS256 with a human password falls to hashcat mode 16500 in minutes. Use 256-bit CSPRNG secrets or asymmetric keys.
  • Treating the payload as confidential. Base64 is not encryption. Anything in a JWT payload is public to its holder — use JWE or keep sensitive claims server-side.

Code equivalents

Fail-closed verification in the two most common stacks — the exact pattern each attack in this sheet fails against.

StackPinned verification
Node (jsonwebtoken)jwt.verify(token, key, { algorithms: ['RS256'], audience: 'api', issuer: 'auth' }) — no header-driven choices.
Python (PyJWT)jwt.decode(token, key, algorithms=['RS256'], audience='api', issuer='auth') — pinned family and claims.
Key handlingkid resolves against a server-side map; JWKS URLs are pinned; secrets are 256-bit CSPRNG output from a secrets manager.

Frequently asked questions

What is the first JWT attack to test on my own API?

alg=none, because it is the fastest: set the header to none, strip the signature, and see if the server accepts it. Then RS256-to-HS256 confusion if you use asymmetric keys, then claim validation (exp, aud, iss).

Is RS256-to-HS256 confusion still a real problem?

Yes — it reappears whenever verification reads the algorithm from the token instead of pinning it per key type. Modern library defaults help, but custom verification code recreates the bug constantly.

How long should an HMAC secret be?

At least 256 bits of CSPRNG output (32 random bytes, ~43 base64 characters). Anything human-memorable falls to offline cracking with hashcat mode 16500.

Does token theft via XSS make all this moot?

It makes storage choices matter: HttpOnly Secure SameSite cookies for browser sessions, short exp times, refresh rotation and revocation — so a stolen token has a small, revocable window.

Are these techniques legal to test?

Only against systems you own or have explicit written permission to assess. Forging tokens against third-party services is unauthorized access, full stop.

Privacy note

All processing happens in your browser. The values you enter never leave your device and are never transmitted to ToolPlex.