The none Algorithm: Forging a JWT a Server Accepts Without a Signature
The challenge
This API authenticates you from the claims inside your JWT. The header says alg:HS256, but the server has a classic flaw: it also accepts a token whose header says alg:none, treating it as already valid with no signature to check. In the workbench, switch the header algorithm to none and rewrite the payload so role becomes admin. The token rebuilds live as you type. Copy the whole forged token and submit it.
What you'll learn
- Understand what the JWT header alg field controls
- Explain why honouring alg:none disables signature verification
- Forge an admin token by switching the algorithm to none and editing the payload
- Recognise alg:none acceptance as a critical authentication bypass
- Know that a server must pin the expected algorithm rather than trust the token's header
Skills tested
Prerequisites
- A JWT is three base64url parts: header, payload, signature
- Claims like role and user live in the payload
- Basic JSON editing
How it works
A JSON Web Token carries an algorithm name in its header, for example {"alg":"HS256","typ":"JWT"}. The intent is that the server reads alg, then verifies the signature with that algorithm and a secret key. The fatal mistake some implementations make is to trust the attacker-controlled header to choose the algorithm. If the header says alg:none and the library honours it, the server treats the token as legitimately unsigned and performs no verification at all.
That turns the JWT into a plain, editable list of claims. Because nothing checks the signature, you can rewrite any claim you like. Here the access decision is the role claim, so you switch the header to {"alg":"none","typ":"JWT"} and change "role":"user" to "role":"admin". The workbench re-encodes both segments and rebuilds the token. The third (signature) segment no longer matters; an alg:none token is commonly sent with an empty signature, which is why a trailing dot with nothing after it is also accepted.
The whole class of bug exists because the algorithm should be a server-side decision, never something the caller can downgrade. Pin it.
Common mistakes
- Only editing the payload. If you leave the header as HS256, the original signature is now wrong - this attack needs the header switched to
noneso the server skips the check. - Trying to compute a real signature. The point of
alg:noneis that you do not need one; do not waste time forging a valid HMAC. - Changing the wrong claim. Access here is decided by
role; set it toadmin, notuserorsub. - Submitting the decoded JSON. Submit the rebuilt, re-encoded token (or its admin payload segment), not the human-readable claims.
How to defend against it
Never let the token's own header decide whether or how to verify it. The server must choose the algorithm and reject anything that disables verification.
- Pin the expected algorithm server-side and reject
alg:none(and any unexpected alg) outright before processing claims. - Use a vetted library version and pass the algorithm explicitly to the verify call; never rely on the library's default to read alg from the token.
- Derive authorization only from claims on a token whose signature has been verified with the correct key.
- Prefer short-lived tokens and, for sensitive roles, server-side session checks so one forged token is not total compromise.