CodePark/ questions / JWT in depth
START PRACTICINGPRACTICE
Backend question · Auth & security › JWT in depth

Tokens are issued with RS256. An older JWT library verifies them like this. An attacker signs a forged token with HS256, using the public key's PEM text as the HMAC secret, and sets alg: HS256 in the header. What is this, and how do you stop it?

const publicKey = fs.readFileSync("public.pem");
const claims = jwt.verify(token, publicKey); // trusts the token's alg
Algorithm confusion; pin the accepted algorithms, e.g. { algorithms: ["RS256"] }, so the token's own header never picks the algorithm

This is algorithm confusion. You stop it by pinning the accepted algorithms, for example { algorithms: ["RS256"] }.

The old library trusts the
alg value in the token's header. When the header says HS256, the library uses the public key's bytes as an HMAC secret. That key is public, so the attacker can compute a valid HMAC too. Pinning the expected algorithm for each key closes the hole, because the token can no longer choose its own algorithm.

"Key leakage; the public key must be kept secret" is the tempting wrong answer. It misses the real flaw: the token was allowed to choose its own algorithm.