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.
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
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.
// 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.
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.