RSTR-JWT-002 — JWT verification disabled
Summary
Code decodes a JWT with the signature-verification step explicitly
turned off (verify: false in jsonwebtoken, verify_signature=False
in pyjwt, noVerify: true etc.). The token payload is taken at face
value — anyone can mint a valid-looking JWT by base64-encoding any
JSON they like, and the application treats it as authenticated.
This defeats the entire point of JWT.
Severity
Critical.
Languages
JavaScript, TypeScript, Python.
What rastray flags
Decode/verify calls with the verification flag disabled:
jwt.verify(token, secret, { verify: false }); // ← flagged
jwt.decode(token, { verify: false }); // ← flagged
jwt.decode(token, options={'verify_signature': False}) # ← flagged
What rastray deliberately does not flag
jwt.decode(token)(without any options) — that decodes-without-verifying but is sometimes legitimate for inspecting a token before separately verifying it. Reviewers should still check those manually.jwt.verify(token, secret)with no options object — verification is on by default.
How to fix it
Always verify the signature and pin the expected algorithm(s):
const decoded = jwt.verify(token, PUBLIC_KEY, {
algorithms: ['RS256'],
issuer: 'https://issuer.example.com',
audience: 'my-api',
});
decoded = jwt.decode(
token,
PUBLIC_KEY,
algorithms=['RS256'],
audience='my-api',
issuer='https://issuer.example.com',
)
If you genuinely need the unverified header (e.g. to pick the right
key from a JWKS), use the library's documented "header-only" helper
and still call verify afterwards:
const header = jwt.decode(token, { complete: true }).header;
const key = jwks.getSigningKey(header.kid).publicKey;
const claims = jwt.verify(token, key, { algorithms: ['RS256'] });