Regex audience matching without anchors is a security footgun
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 52/100
- issue の種類
- ドキュメント
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- javascript, node.js
調査の方向性
verify.js の audience チェックと README の audience セクションから始めてください。文字列 audience と RegExp audience が現在どのように説明されているかを確認し、そのうえで、maintainer がどの提案動作を望んでいるのかを確認してください。完了時には、アンカーされていない正規表現 audience のセキュリティ上の影響を明確にし、必要に応じて関連する検証カバレッジも更新してください。
索引モデルが issue の本文から書いたものです。
説明
Summary
When options.audience contains a RegExp, verify() calls audience.test(targetAudience) without enforcing that the regex is anchored. This means a developer who writes:
jwt.verify(token, secret, { audience: /api\.myapp\.com/ });
will inadvertently accept tokens with audiences like evil-api.myapp.com.attacker.com — the . matches any character and there are no ^/$ anchors.
The string comparison path (audience === targetAudience) is strict. The regex path silently shifts the security burden to the caller.
Reproduction
const jwt = require('jsonwebtoken');
const secret = 'test-secret';
const token = jwt.sign({ aud: 'evil-api.myapp.com.attacker.com' }, secret);
// Developer intends to only accept "api.myapp.com"
jwt.verify(token, secret, { audience: /api\.myapp\.com/ }, (err, decoded) => {
console.log(err); // null — no error!
console.log(decoded); // token accepted despite malicious audience
});
Impact
This is not a vulnerability in the library itself — the regex works as designed. But it's a footgun: developers who mix string and regex audience checks may not realize the security model differs between the two paths. The string path is exact-match. The regex path accepts partial matches unless the developer manually adds ^ and $.
Given that audience validation is a security-critical check, the gap between "looks like it works" and "actually secure" is a concern.
Suggestions (pick any)
- Document it prominently — Add a note to the README's audience section warning that regex audiences must be anchored to avoid partial matches.
- Warn on unanchored regexes — If the regex source doesn't start with
^or end with$, emit a console warning or throw. - Auto-anchor — Wrap unanchored regexes in
^(?:...)$before testing. This would be a breaking change for anyone relying on partial matches intentionally.
Option 1 is the lowest-friction fix. Option 2 provides defense-in-depth without breaking existing behavior.
Relevant code
return audiences.some(function (audience) {
return audience instanceof RegExp ? audience.test(targetAudience) : audience === targetAudience;
});
- 主要言語
- 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 が 230 日前に担当しました。 オープン
難易度 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 が 25 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 65/100
auth0/node-jsonwebtoken#1046 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 10/100
auth0/node-jsonwebtoken#1034 ·
auth0/node-jsonwebtoken の issue をすべて見る
似ている issue
-
area: docs good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 64/100
メンテナーはふだん 1 日以内に返信
-
Support
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
openseadragon/openseadragon#2996 ·
メンテナーはふだん 3 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
jfromaniello/url-join#134 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100