Stop 11 of 42 · The ID Desk · JWT attacks

Forging a signed badge

The bank’s badges are stamped with a secret stamp so guards can tell they are real. But the guard has sloppy rules: he follows whatever the badge says about itself. Mallory writes her own badge, says “no stamp needed”, and gives herself the title Manager.

Severity Info to CriticalCategory Auth WeaknessThe ID DeskSources checked 25 Oct 2026

Watch it happen

Play it as

Mallory makes her own badge claiming to be a manager and says no signature is needed. The guard accepts it.

Arrival

Mallory walks up to the front door. Real badges carry a name and a role, and are pressed with the bank’s secret stamp. The guard checks that stamp.

Guard says: Badge, please.
1 / 5

In bank terms and app terms

In the bankIn your app
Signed badgeA JSON Web Token (JWT)
Secret stampThe signing secret or private key
“No stamp needed”alg: none, a token that skips signature checking
Role written on the badgeClaims like role or is_admin inside the token

Are you exposed?

You might be exposed if…
  • Your JWT secret is short, human-readable or a placeholder like “secret” or “your-256-bit-secret”.
  • You call jwt.decode() or an old library version without forcing the algorithm (algorithms: ["HS256"]).
  • Tokens have no exp claim, or your server trusts role / is_admin from the token without checking elsewhere.
What to do about it
  1. Verify with jwt.verify(), pass an explicit algorithms list, and reject alg: none.
  2. Use a long random secret (32+ bytes) from an env var, or let your auth provider (Supabase, Firebase, Clerk) manage tokens.
  3. Always set a short exp, and look up roles in your database instead of trusting the token’s claim.

Track these in your to-do list →

It has happened to real companies

Real-world breaches

jsonwebtoken CVE-2015-9235 (2015) — Versions of the popular jsonwebtoken npm library before 4.2.2 could be tricked into verifying a token with an RSA public key as if it were a shared secret, letting attackers forge tokens that looked valid. Several JWT libraries from the same era also accepted alg: none, which skips signature checking entirely.

Palo Alto Networks PAN-OS CVE-2020-2021 (2020) — A SAML signature-validation flaw, when the identity provider's certificate was not being checked, let attackers bypass authentication on PAN-OS. It scored the maximum severity (CVSS 10). This one is SAML rather than JWT, but the lesson is the same: a signature you don't verify properly protects nothing.

What it looks like in code

// BAD: No algorithm restriction — the token picks its own algorithm (alg: none on old libraries, or HS256 against an RSA public key)
const payload = jwt.verify(token, SECRET)

// BAD: Weak secret
const JWT_SECRET = "secret"
const token = jwt.sign(payload, JWT_SECRET)

// BAD: No expiration
const token = jwt.sign({ userId: "123", role: "admin" }, SECRET)
// Missing: expiresIn option

Ask your AI tool to fix it

Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.

Prompt
Review all JWT handling in my project. Ensure tokens are verified (not just decoded) with an explicit algorithms allow-list and never alg: none, that the signing secret is 32+ random bytes read from an environment variable, that every token has a short exp, and that authorization decisions look up the user’s role in the database instead of trusting a role claim. List every change.

Where this comes from

The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.

Spot a mistake or something out of date? Report a correction · How these guides are made and checked

Go deeper in isitsecure

The free, open-source scanner checks for most of the problems in these guides.