Tamper the Token: Forging a JWT When the Signature Is Not Checked
The challenge
This dashboard decides what you can see from the role claim inside your JWT - and it never checks the signature, so the claim is yours to change. In the workbench, edit the payload so role becomes admin. The token rebuilds live as you type. Copy the whole forged token (all three parts, including the dots) and submit it.
What you'll learn
- Understand that a JWT signature only protects claims if the server verifies it
- Tamper a payload claim and observe the token re-encode in real time
- Forge a privilege-escalated token by changing the role claim to admin
- Recognise signature-verification gaps (skipped checks, alg:none) as critical auth flaws
Skills tested
Prerequisites
- Awareness that JWTs carry claims like role and user id
- Basic JSON editing
How it works
A JSON Web Token splits into three base64url parts: header, payload, and signature. The signature is the only thing that makes the payload trustworthy - it is a keyed hash over the header and payload, so if anyone edits a claim, the signature no longer matches and a correct server rejects the token. Take that check away and the JWT becomes what it physically is: a plain, editable list of claims with a useless string stapled on the end.
That is the flaw here. The dashboard reads role straight from the payload to decide access, but it never verifies the signature (a common real bug, alongside accepting alg:none). So you can simply rewrite the claim. In the workbench you decode the payload, change "role":"guest" to "role":"admin", and the tool re-encodes the payload and rebuilds the token live. The original signature - now mathematically wrong - is carried along unchanged, and because the server does not check it, your forged token authenticates you as an administrator.
The point of the exercise is the act of forging, not reading. Decoding alone tells you nothing an honest token would not; the vulnerability only appears when you change a claim and the server still trusts it.
Common mistakes
- Only reading the payload. Decoding is free and proves nothing - the bug is that you can change a claim and still be trusted.
- Editing the wrong field. The access decision is the
roleclaim; change its value toadmin, not the user or sub. - Submitting the decoded JSON. The answer is the rebuilt, re-encoded token (or its payload segment), not the human-readable claims you typed.
- Trying to fix the signature. You do not need a valid signature here - the whole point is that the server never checks it.
How to defend against it
The fix is non-negotiable: always verify the signature with the expected algorithm and key before trusting a single claim, and reject alg:none outright. Never make an authorization decision on an unverified token.
- Verify the JWT signature on every request, pinning the algorithm server-side (no
none, no client-chosen alg). - Derive authorization from verified claims only, and prefer short-lived tokens.
- Consider server-side sessions or token revocation for sensitive roles so a single forged or stolen token is not game over.