JKUFactory and X5UFactory follow HTTP redirects when they fetch a key set
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 48/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
調査の方向性
Read the key set documentation and the security recommendations, then inspect UrlKeySetFactory::sendSymfonyRequest() on 4.2 or UrlKeySetFactoryTrait::sendRequest() on 4.3, along with JKUFactory::loadFromUrl() and X5UFactory::loadFromUrl(). Decide how the affected release should handle redirects and document safe URL use; done means the guidance covers the redirect risk and the workaround, without implying that URLs from tokens are safe to load.
索引モデルが issue の本文から書いたものです。
説明
Version(s) affected
3.3.0 to 3.4.12, 4.0.0 to 4.0.8, 4.1.0 to 4.1.10, 4.2.0 to 4.2.5, 4.3.x-dev (with a Symfony HTTP client; on 3.4.x the PSR-18 path does whatever the PSR-18 client does)
Description
JKUFactory::loadFromUrl() and X5UFactory::loadFromUrl() send their request with the headers option only (UrlKeySetFactory::sendSymfonyRequest() up to 4.2, UrlKeySetFactoryTrait::sendRequest() on 4.3). The redirect policy of the client therefore applies. With Symfony's defaults (HttpClient::create(), the framework's http_client service), up to 20 redirects are followed, to any host and from https to http, and the body of the last response is used as the key set. The final URL is never compared with the requested one.
As a result:
- the host behind a configured
jku/x5uURL can make the application server send a GET request to an address of its choice, such as a loopback or internal service. The answer does not come back to that host. Headers passed toloadFromUrl()are forwarded to the redirect target, exceptAuthorizationandCookie, which Symfony drops when the host changes; - an
httpskey set URL that redirects tohttpis loaded without TLS; - an application that takes the URL from the
jku/x5uheader of a token and checks its host against a list of allowed hosts is bypassed by any redirect on an allowed host, an open redirect for instance: the key set, and so the key that verifies the token, come from the redirect target.
The library and the bundle only load configured URLs, and the documentation never takes the URL from a token. It does not warn against doing so either.
How to reproduce
use Jose\Component\KeyManagement\X5UFactory;
use Symfony\Component\HttpClient\HttpClient;
// https://keys.example.com/x5u answers "302 Found", "Location: http://127.0.0.1:8080/admin/cache/purge?all=1"
$keySet = (new X5UFactory(HttpClient::create()))->loadFromUrl('https://keys.example.com/x5u');
// The local service receives "GET /admin/cache/purge?all=1" and its "{}" answer becomes an empty key set.
// JKUFactory sends the same request, then throws "Invalid data.".
Possible Solution
Workaround available today: give the factories a client that does not follow redirects, for example a scoped client with max_redirects: 0 (a 3xx answer then fails), possibly wrapped in NoPrivateNetworkHttpClient.
- 4.x: document the workaround on the key set page, and say in the security recommendations that
jku/x5umust not be taken from a token; an application that does it anyway should compare the full URL with an exact list and refuse redirects. An opt-in could come with 4.3.0 (an extra constructor argument read withfunc_num_args(), or a bundle option). - 5.0.0: refuse redirects by default and treat any non-2xx answer as a failure, with an explicit opt-in.
Refusing redirects in a patch release would stop every key set URL that redirects today (http to https, a moved endpoint), so it is not a patch-level change.
Additional Context
Found by the Anthropic OSS Scanner (ANT-2026-5HOQLEPP).
On 4.3, the docblock of UrlKeySetFactoryTrait ("Fetches the document a "jku" or a "x5u" header parameter points to") reads as an invitation to load URLs taken from tokens and is worth rewording.
- 主要言語
- PHP
- スター
- 954
- フォーク
- 119
- 平均マージ
- 48分
- マージ済み PR(30日)
- 17
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
web-token/jwt-framework のほかの issue
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
web-token/jwt-framework#757 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 3/5 1〜2日 初心者へのやさしさ 68/100
web-token/jwt-framework#773 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 4/5 3〜5日 初心者へのやさしさ 57/100
web-token/jwt-framework#772 ·
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
web-token/jwt-framework#771 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
web-token/jwt-framework#770 ·
メンテナーはふだん 1 日以内に返信
web-token/jwt-framework の issue をすべて見る
似ている issue
-
enhancement priority Sales
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
novalo-dev/Prestashop-MCP-Server#201 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
Include flows spanning the full report time window対応中かも @somethingwithproof が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
Cacti/plugin_flowview#306 ·
メンテナーはふだん 1 日以内に返信
-
bug origin: upstream priority: low
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
mattytap/Mattytap-Sermons#105 ·
-
priority:low type:bug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
crazy-goat/workerman-bundle#1189 ·
メンテナーはふだん 1 日以内に返信