jwt.verify accepts tokens with unrecognized `crit` header extensions (RFC 7515 §4.1.11)
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 48/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- javascript, node.js
調査の方向性
verify.js の decoded-header パスから開始し、提供された RSA の再現を実行して、その動作を RFC 7515 §4.1.11 および jose の validate_crit.ts リファレンスと比較します。検証中にサポートされていない、または不正な crit ヘッダーが拒否され、呼び出し元の opt-in 動作がテストでカバーされていれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Description
[email protected] 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 [email protected] 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 [email protected]
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
[email protected] 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
- 主要言語
- JavaScript
- スター
- 18.2k
- フォーク
- 1.3k
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
auth0/node-jsonwebtoken のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
auth0/node-jsonwebtoken#1042 · コメント 1 件 ·
-
`jwt.sign()` callback is executed twice for "The payload already has an "..." property" errors対応中かも @cobyfrombrooklyn-bot が 228 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
auth0/node-jsonwebtoken#1000 · コメント 2 件 · リアクション 1 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
auth0/node-jsonwebtoken#1048 ·
-
verify() resolves a string secret by attempting createPublicKey() first, costing 4x-52x on the HS* path対応中かも @Hashim1999164 が 23 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 65/100
auth0/node-jsonwebtoken#1046 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 10/100
auth0/node-jsonwebtoken#1034 ·
auth0/node-jsonwebtoken の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 71/100
yjh051108/dsh-routing-suite#227 ·
-
needs-triage release-watch
難易度 1/5 1時間未満 初心者へのやさしさ 76/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
dusk-network/exu#17 ·
-
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
jspreadsheet/ce#1809 ·
-
documentation
難易度 1/5 1時間未満 初心者へのやさしさ 91/100
githubnext/gh-aw-workshop#4458 ·
メンテナーはふだん 1 日以内に返信