
Proof-of-concept exploit for CVE-2026-18963, demonstrating unauthenticated account takeover by bypassing the reset-credentials flow in web applications.
★ CVE-2026-18963 Keycloak Reset-Credentials Flow Bypass PoC ★
https://github.com/user-attachments/assets/ebed1e64-a40c-4333-be18-9acbadd655b0
CVE-2026-18963 is a critical unauthenticated account takeover vulnerability in the Keycloak
keycloak-servicescomponent (CVSS 9.1). A flaw in the reset-credentials authentication state machine allows a remote attacker to bypass the email-verification step and reach the password-update form without possessing the reset link. By targeting a known username, an attacker can set a new password and take control of the victim's account without authentication or user interaction.
The vulnerable flow stores the credential-selector state as a session-wide authentication note instead of binding it to the execution that displayed the selector. Re-entering the reset flow can therefore reuse stale selector state for another execution. In affected versions, the reset-email authenticator also accepts an action without confirming that it was reached through a valid email action token. Chaining these behaviors advances the attacker directly to UPDATE_PASSWORD.
| Category | Version |
|---|---|
| Vulnerable | Keycloak 26.0.0 ≤ version < 26.4.15 |
| Vulnerable | Keycloak 26.5.0 ≤ version < 26.6.6 |
| Vulnerable | Keycloak 26.7.0 ≤ version < 26.7.2 |
| Patched | 26.4.15, 26.6.6, 26.7.2 (respective release branches) |
This lab uses Keycloak 26.7.1.
Build and run the vulnerable Keycloak 26.7.1 environment. The image imports a test realm with the vulnerable reset-credentials flow enabled, a seeded victim account, and an EQST portal with a protected flag page.
docker build -t cve-2026-18963 .
docker run --rm -d \
--name cve-2026-18963 \
-p 9105:9105 \
-e PORTAL_PUBLIC_URL=http://127.0.0.1:9105 \
cve-2026-18963
Wait for Keycloak to start, then open the portal:
http://127.0.0.1:9105
| Precondition | State in this lab |
|---|---|
| Keycloak | 26.7.1 (vulnerable) |
| Realm | cve-lab |
| Forgot password | enabled |
| Target account | victim |
| Keycloak base URL | http://127.0.0.1:9105/keycloak |
The included exploit.py automates the reset-flow state manipulation, requests the password-update form without consuming an email action token, changes the victim's password, and verifies the takeover by requesting an access token with the new credentials.
Install the Python dependency:
python3 -m pip install requests
Run the exploit with the Keycloak URL, victim username, and a new password:
# python3 exploit.py <keycloak-url> <victim> <new-password>
python3 exploit.py \
http://127.0.0.1:9105/keycloak \
victim \
'NewPassword1!'
A successful run prints:
[*] selector note set via tryAnotherWay
[*] victim submitted: victim
[*] update-password form served without an action token
[+] VULNERABLE - victim password is now 'NewPassword1!'
Open http://127.0.0.1:9105, click LOGIN, and authenticate as victim with the new password to confirm the account takeover.