Lab · You are the attacker

JWT Tampering Lab

A target API issues you a JWT as a regular user. Your job: become an admin without ever knowing the server's signing key. The lab uses two server modes — vulnerable (the default) and hardened — so you can see exactly which checks would have stopped you.

Your mission

You logged into https://app.cyberlab.example as bob, a regular user. The site issued you the JWT below. Reading other people's email is locked behind role: admin, which the server checks by reading the role claim out of your token.

  1. Decode the token. Read its claims.
  2. Change your role to admin (and/or change the alg to none). Re-assemble the token.
  3. Send the forged token at the “Admin Panel” endpoint and see what the vulnerable server does.
  4. Switch the server to Hardened mode. Try the same forged token. Read the rejection reason.
JWT Tampering Workbench
Server mode:
Attacker workbench (your browser) tampering...
Header (try changing alg to "none")
Payload (try changing role to "admin")
Signature (leave empty if alg is none; otherwise the server's HMAC fails)
Reassembled token
Server — app.cyberlab.example VULNERABLE
Awaiting request. Modify the token on the left and click Send.
Server is in VULNERABLE mode. Default validation is sloppy. Forge away.

If you're stuck — the canonical attack

  1. Click Set alg: none. The header changes from {"alg":"HS256",...} to {"alg":"none",...}.
  2. Click Set role: admin. The payload's role claim changes from "user" to "admin".
  3. Click Send to /admin/users. Watch the vulnerable server's log — it accepts the token because it honored the alg in the header (which now says “none”, meaning no signature check). You see other users' emails.
  4. Switch to Hardened. Click Send again. The hardened server pins alg: HS256, rejects anything else, and rejects HS256 tokens whose HMAC doesn't validate against its secret key.
What you just learned

The vulnerable server made one design choice: it called a library function that auto-detected the algorithm from the token header. That single choice eliminated the entire signature check. The fix was equally small: pin the expected algorithm at the verifier and reject anything else.

The wider lesson: trust nothing the token says about how to verify itself. The token can claim any algorithm; your verifier must enforce the one you actually expect, and validate every claim (iss, aud, exp) against your own expectations — not against what the token requests.

A real attacker doesn't get the convenient editor above. They use curl and a Base64 tool. The math is identical.