The JWT mistakes that still work in 2026
Algorithm confusion, unverified signatures and secrets that were never secret. A tour of the JWT failures I keep finding in labs, and what each one actually requires to exploit.
JSON Web Tokens are not insecure. Almost every JWT vulnerability is a library being used in a way the specification technically permits and no sensible person wanted.
Here are the ones I still reproduce in labs, in roughly the order I check them.
1. The signature is never verified
The most common and the least interesting. The application decodes the token and reads the claims without calling the verification function at all.
// This decodes. It does not verify. They are different functions and the
// naming does not help.
const claims = jwt.decode(token);
if (claims.role === "admin") { /* ... */ }Test: change a claim, re-encode without touching the signature, send it. If it is accepted, the signature was decoration.
2. alg: none
The specification defines an "unsecured" JWS with the algorithm none and an empty signature. Some libraries used to honour it by default.
{ "alg": "none", "typ": "JWT" }Mostly dead in maintained libraries, still alive in pinned dependencies and hand-rolled parsers. Cheap to test, so always worth the thirty seconds.
3. Algorithm confusion: RS256 to HS256
This one is genuinely elegant, which is why it keeps working.
The server issues tokens signed with RS256 and verifies them with its public key. An attacker changes the header to HS256 and signs the token using that same public key as the HMAC secret. A verification function that picks its algorithm from the token header will now happily HMAC-verify with a key everyone can read.
The root cause is the same as none: trusting the token to describe how it should be checked.
// The bug: the algorithm comes from attacker-controlled input.
jwt.verify(token, publicKey);
// The fix: the server decides, not the token.
jwt.verify(token, publicKey, { algorithms: ["RS256"] });Getting the public key is usually trivial — a /.well-known/jwks.json, a certificate, or the key material published alongside the API docs. It is public. That is the point of it.
4. Weak HMAC secrets
If the token is HS256 and the secret is a word, it is recoverable offline. No requests to the target, no rate limit, no logs.
# Against a token from my own lab.
hashcat -a 0 -m 16500Related
Understand the application before you test it
Scanners find what they were told to look for. The bugs that matter live in the gap between what an application believes about itself and what it actually enforces.
- Web Security
- OWASP
- Methodology
IDOR is still everywhere, and here is why
Broken object level authorisation stays the most common serious finding in web applications. Not because it is hard to fix, but because of where the check has to live.
- Web Security
- OWASP
- Bug Bounty
The JWT that trusted its own header
Personal lab
A lab write-up on an authentication bypass through JWT algorithm confusion — the classic 'alg: none' and its slightly less obvious RS256-to-HS256 cousin.
- Write-ups
- Web Security
- Authentication

