JKUFactory and X5UFactory follow HTTP redirects when they fetch a key set

オープン
#762 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
php, symfony

調査の方向性

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 の本文から書いたものです。

説明

enhancement
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/x5u URL 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 to loadFromUrl() are forwarded to the redirect target, except Authorization and Cookie, which Symfony drops when the host changes;
  • an https key set URL that redirects to http is loaded without TLS;
  • an application that takes the URL from the jku/x5u header 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/x5u must 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 with func_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 を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

web-token/jwt-framework のほかの issue

web-token/jwt-framework の issue をすべて見る

似ている issue

PHP の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。