When you verify a JWT, the token itself declares which algorithm signed it, and if you do not pin the algorithm your code will trust that declaration. An attacker can set the algorithm to none, or switch an RS256 token to HS256, to bypass verification and forge tokens. Always tell the verifier exactly which algorithm to accept.
Why it's a problem
With no pinned algorithm, a token claiming alg:none may be accepted with no signature at all, letting anyone forge any claims. The RS256-to-HS256 confusion attack is subtler: the attacker signs a token with your public key as if it were an HMAC secret, and a verifier that accepts either algorithm treats it as valid. Either way, your authentication is defeated.
The pattern
// trusts the algorithm the token declares const payload = jwt.verify(token, key);
The fix
// only accept the algorithm you actually use
const payload = jwt.verify(token, key, {
algorithms: ["RS256"],
});Why AI tools write this
The two-argument verify call is the shortest form and works for legitimate tokens, so it is the natural completion. Pinning the algorithm is an extra option that security requires but a functional test never needs, so it is easy for it to be left off.
The quick fix
- Pass an explicit algorithms allowlist to your JWT verify call.
- Never allow alg:none, and do not accept both HMAC and RSA algorithms on the same key.
- Verify the signature; never trust a decoded payload you have not verified.