← All fixes

Fix it

Verifying a JWT without pinning the algorithm — how to fix it

High severityCWE-347 (Improper Verification of Cryptographic Signature)

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.

Want to know if this pattern is already in a repo you shipped? Scan a public repo free, no account needed.

Scan a repo →

Related: what a JWT is

JWT Verified Without Pinning the Algorithm (alg:none) — The Fix: Prbl