Skip to contentExploitQuest

Lesson 3 of 3 in Broken Authentication

Verify What You Issued

The fix is to stop letting the token choose how it is checked, and to stop trusting the claims it carries about privilege. Pin the algorithm, and read authority from the server, not from the cookie.

2 min read

Not yet reviewed

Wrenlearner

So I just refuse tokens with alg:none?

Rookmentor

That closes this door and leaves the frame. The real fix is to stop asking the token how to check itself at all — you issued it, so you already know.

Pin the algorithm

The server issued the token, so the server knows how it was signed. It should verify with that algorithm and no other — never with the one the token's own header names. A verifier that reads alg from the token is taking instructions from the thing it is meant to be checking.

Letting the token choose (the bug)

const alg = header.alg
return verifyWith(alg, token)

Pinning the algorithm (the fix)

return verifyWith('HS256', token)   // never header.alg

The fix hard-codes the one algorithm the server signs with. none is not on the menu, and neither is an attacker downgrading an RS256 token to be "verified" with the public key as an HMAC secret — the other classic version of this bug.

Do not trust claims about privilege

The second half of the forgery worked because the app read role from the token. A token can safely carry *identity* — who you are — because that is what the signature attests. It should not carry *authority* the server then trusts blindly. Re-read the role from the database for the user the token names, so a forged or stale claim buys nothing.

The non-fixes

Two habits look like fixes here and are not, in the now-familiar way — they patch a symptom and leave the mechanism.

block "alg":"none"        the RS256->HMAC downgrade still gets you in
put the role in the token  signed, but still authority the client carries
  1. Line 1Refusing the literal string none stops this exact payload and not the family. Pinning the algorithm stops all of them, because the server stops consulting the header at all.
  2. Line 2A signed role claim is not tamper-*proof* the moment the signature can be bypassed — and even when it cannot, it goes stale: revoke someone's access and their old token still says they have it. Authority belongs server-side.

Signed tokens are everywhere and mostly fine. What is the one-line rule that separates the safe uses from this lab?