jwt.verify accepts tokens with unrecognized `crit` header extensions (RFC 7515 §4.1.11)
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
- Domain
- authentication, security
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 ignoringcritwill 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:
- If
header.critexists, it must be a non-empty array of strings (per §4.1.11). - Reject if
critlists any name that this library does not implement. Sincejsonwebtokendoes not implement anycritextensions, the simplest correct behavior is to reject any token whosecritis non-empty unless the caller opts in via an option likecrit: ['name1', ...]enumerating extensions the caller has handled out-of-band.
jose's implementation is a small reference.
Environment
jsonwebtoken9.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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from auth0/node-jsonwebtoken
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
auth0/node-jsonwebtoken#1042 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
auth0/node-jsonwebtoken#1000 · 2 comments · 1 reaction ·
-
Difficulty 4/5 3-5 days Newbie friendliness 65/100
auth0/node-jsonwebtoken#1046 ·
-
Difficulty 5/5 Over a week Newbie friendliness 10/100
auth0/node-jsonwebtoken#1034 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
auth0/node-jsonwebtoken#1031 ·
All issues in auth0/node-jsonwebtoken
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
mksglu/context-mode#1200 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
neondatabase/website#5944 ·
-
module: core
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
bigbluebutton/bigbluebutton#25849 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
jaegertracing/jaeger-ui#4506 ·