Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

jwt.verify accepts tokens with unrecognized `crit` header extensions (RFC 7515 §4.1.11)

Open
#1,032 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
48/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
javascript, node.js

Research direction

Start in verify.js at the decoded-header path; run the supplied RSA reproduction and compare its behavior with RFC 7515 §4.1.11 and jose's validate_crit.ts reference. Done means unsupported or malformed crit headers are rejected during verification, with any caller opt-in behavior covered by tests.

Written by the indexing model from the issue text.

Description

Description

jsonwebtoken@9.0.3 accepts JWTs whose JOSE header contains a crit array listing extension Header Parameters that the library does not understand or process. Per RFC 7515 §4.1.11, such tokens must be rejected:

If any of the listed extension Header Parameters are not understood and supported by the recipient, then the JWS MUST be rejected.

A grep of the installed jsonwebtoken@9.0.3 source shows no crit handling at all — the field is silently ignored during verification. As a result, a signer who relies on crit to mandate that verifiers respect an extension (e.g. a key-binding or policy header) gets no enforcement when the verifier is jsonwebtoken, even though the signer marked the extension as critical.

Reproduction
// npm i jsonwebtoken@9.0.3
const jwt = require('jsonwebtoken');
const crypto = require('crypto');

const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 2048 });
const pubPem  = publicKey.export ({ type: 'spki',  format: 'pem' });
const privPem = privateKey.export({ type: 'pkcs8', format: 'pem' });

// Sign a token that declares an extension param as critical
const token = jwt.sign(
  { sub: 'x', role: 'admin' },
  privPem,
  { algorithm: 'RS256',
    header: { crit: ['x-attack-vector'], 'x-attack-vector': true } });

// Verify — RFC 7515 §4.1.11 requires rejection because jsonwebtoken does not
// understand or process the 'x-attack-vector' extension.
console.log(jwt.verify(token, pubPem, { algorithms: ['RS256'] }));

Observed output:

{ sub: 'x', role: 'admin', iat: 1779849601 }

Expected: a verification error (e.g. JsonWebTokenError: critical header parameter 'x-attack-vector' is not understood).

Cross-library comparison

jose@5.10.0 rejects the same token, citing the same RFC clause:

ERR_JOSE_NOT_SUPPORTED: Extension Header Parameter "x-attack-vector" is not recognized

So a deployment that issues tokens with crit-protected extensions via one library and verifies them with jsonwebtoken loses the protection the signer intended.

Why it matters

crit is the mechanism JWS provides for a signer to require that a particular extension header be honored. Concrete examples in the wild:

  • b64 (RFC 7797) — signer asserts the payload is not base64url-encoded; a verifier ignoring crit will treat it as encoded and either fail or, worse, validate a different payload than the one signed.
  • Custom security-policy extensions (e.g. token-binding hints, audience-restriction extensions, replay-protection nonces) where the signer explicitly demands enforcement.

A verifier that silently strips crit defeats the whole purpose of the field as defined in RFC 7515.

Suggested fix direction

In verify.js, after the header is decoded:

  1. If header.crit exists, it must be a non-empty array of strings (per §4.1.11).
  2. Reject if crit lists any name that this library does not implement. Since jsonwebtoken does not implement any crit extensions, the simplest correct behavior is to reject any token whose crit is non-empty unless the caller opts in via an option like crit: ['name1', ...] enumerating extensions the caller has handled out-of-band.

jose's implementation is a small reference.

Environment
  • jsonwebtoken 9.0.3 (current latest on npm)
  • Node v26.0.0
  • macOS 14
Dominant language
JavaScript
Stars
18.2k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from auth0/node-jsonwebtoken

All issues in auth0/node-jsonwebtoken

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.