mediumLogins, sessions and access

JWT Verified Without Pinning the Algorithm

Token verification does not say which signing algorithm it expects.

Why it matters

A JWT carries its own algorithm in the header. When the verifier does not pin one, an attacker can send a token that claims a different algorithm, in the worst case "none" or an HMAC signed with your public key, and some library versions accept it. Pinning the algorithm costs one option and removes the whole class.

What it looks like

This is the shape of code that triggers the rule. AI tools produce it because it works, and nothing tells them it is unsafe.

jsonwebtoken verify with no options
const jwt = require('jsonwebtoken');
function auth(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  req.user = jwt.verify(token, process.env.JWT_SECRET);
  next();
}

The smallest fix

minimal patch
const payload = jwt.verify(token, process.env.JWT_SECRET, {
  algorithms: ['HS256'],
  issuer: 'your-app',
});

The better fix

If you have a few more minutes, this is the approach that holds up as the app grows.

safe alternative
// jose
const { payload } = await jwtVerify(token, secret, { algorithms: ['HS256'], issuer: 'your-app', audience: 'your-api' });
// fast-jwt
const verify = createVerifier({ key: process.env.JWT_SECRET, algorithms: ['HS256'] });

Let your AI tool fix it

When the scanner finds this in your project, it fills in the file and line for you. This is the prompt it gives you to paste into Claude Code, Cursor or whatever you use.

In [the file] at line [the line number] a JWT is verified without an algorithm allow-list: [the flagged code]. Add algorithms: ['HS256'] (or the RS/ES algorithm actually used to sign) to the verify options, make sure the secret comes from the environment and is never empty, and add a test that a token with alg "none" is rejected.

How to check the fix worked

1. Build a token with the header alg set to "none" and no signature;
   confirm verification throws.
2. Confirm a correctly signed token still verifies.