8000
  • fix: prevent a stale id token from allowing session takeover by shawkins · Pull Request #54942 · keycloak/keycloak · GitHub
    [go: up one dir, main page]

    Skip to content

    fix: prevent a stale id token from allowing session takeover - #54942

    Merged
    shawkins merged 1 commit into
    keycloak:mainfrom
    shawkins:iss54691
    Nov 12, 2026
    Merged

    shawkins merged 1 commit into
    keycloak:mainfrom
    shawkins:iss54691

    Conversation

    @shawkins
    @shawkins shawkins commented Nov 9, 2026 •
    Copy link
    Copy Markdown
    Contributor

    consolidated session cleanup, and changed how createOrJoinLogoutSession uses the userSession

    also adding more test coverage for orphaned state

    closes: #54691
    closes: CVE-2026-107124

    @shawkins
    shawkins marked this pull request as ready for review November 9, 2026 20:00
    @shawkins
    shawkins requested a review from a team as a code owner November 9, 2026 20:00
    Copilot AI balanced review requested due to automatic review settings November 9, 2026 20:00
    Copilot AI left a comment
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Changes recommended

    Logout handling can delete unrelated login tabs and reuse another session’s logout state, potentially suppressing client logout notifications.

    2 open issues
    What changed in this PR

    This PR addresses stale-ID-token session takeover by separating logout authentication roots from user-session IDs and consolidating session cleanup.

    Changes:

    • Uses random logout root IDs with explicit session bindings and earlier stale-token validation.
    • Cleans up paired authentication roots and binds authorization codes to users.
    • Adds regression coverage and documents rolling-upgrade behavior.
    File Description
    tests/​base/​src/​test/​java/​org/​keycloak/​tests/​session/​AdminSessionDeletionTest.java Updates logout-root isolation assertions.
    tests/​base/​src/​test/​java/​org/​keycloak/​tests/​oauth/​AuthorizationCodeTest.java Tests code exchange and user-binding rejection.
    tests/​base/​src/​test/​java/​org/​keycloak/​tests/​forms/​StaleAuthSessionLogoutTest.java Adds fixation and orphaned-session regression coverage.
    tests/​base/​src/​test/​java/​org/​keycloak/​tests/​forms/​LogoutSessionReuseTest.java Tests logout continuity, cookie safety, and cleanup.
    services/​src/​test/​java/​org/​keycloak/​protocol/​oidc/​utils/​OAuth2CodeTest.java Tests user-ID serialization and legacy compatibility.
    services/​src/​main/​java/​org/​keycloak/​services/​resources/​admin/​ClientScopeEvaluateResource.java Consolidates temporary-session cleanup.
    services/​src/​main/​java/​org/​keycloak/​services/​resources/​account/​AccountRestService.java Uses shared cleanup during application revocation.
    services/​src/​main/​java/​org/​keycloak/​services/​managers/​UserSessionManager.java Removes orphaned roots after offline-session revocation.
    services/​src/​main/​java/​org/​keycloak/​services/​managers/​AuthenticationManager.java Adds random logout roots, explicit bindings, and paired cleanup.
    services/​src/​main/​java/​org/​keycloak/​protocol/​oidc/​utils/​OAuth2CodeParser.java Validates authorization-code user binding.
    services/​src/​main/​java/​org/​keycloak/​protocol/​oidc/​utils/​OAuth2Code.java Stores the user ID with authorization codes.
    services/​src/​main/​java/​org/​keycloak/​protocol/​oidc/​refresh/​DefaultRefreshTokenProvider.java Resolves corresponding online sessions and cleans empty sessions.
    services/​src/​main/​java/​org/​keycloak/​protocol/​oidc/​OIDCLoginProtocol.java Includes the user ID when issuing codes.
    services/​src/​main/​java/​org/​keycloak/​protocol/​oidc/​grants/​ResourceOwnerPasswordCredentialsGrantType.java Removes paired roots for offline direct grants.
    services/​src/​main/​java/​org/​keycloak/​protocol/​oidc/​grants/​OAuth2GrantTypeBase.java Reuses consolidated offline-access cleanup.
    services/​src/​main/​java/​org/​keycloak/​protocol/​oidc/​endpoints/​LogoutEndpoint.java Validates hints earlier and clears reused logout request data.
    services/​src/​main/​java/​org/​keycloak/​authorization/​admin/​PolicyEvaluationService.java Uses paired cleanup for evaluation sessions.
    services/​src/​main/​java/​org/​keycloak/​authentication/​authenticators/​browser/​CookieAuthenticator.java Restarts login when expiry cleanup removes its root.
    server-spi/​src/​main/​java/​org/​keycloak/​sessions/​AuthenticationSessionProvider.java Adds root-session removal by ID.
    docs/​documentation/​upgrading/​topics/​changes/​changes-next-cve-2026-107124.adoc Documents in-flight logout effects during rolling upgrades.

    Review effort: Balanced

    @shawkins
    shawkins marked this pull request as draft November 10, 2026 01:35
    @shawkins
    shawkins marked this pull request as ready for review November 10, 2026 12:44
    @mposolda mposolda left a comment
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    @shawkins Thanks!

    Copilot AI balanced review requested due to automatic review settings November 11, 2026 14:01
    @mposolda mposolda self-assigned this Nov 11, 2026
    Copilot AI left a comment
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🔵 Needs a closer look

    Security-sensitive logout rebinding and cleanup span storage providers, browser/IdP callbacks, and mixed-version clusters, requiring runtime validation beyond static review.

    No open issues 🎉

    2 resolved since last review

    Review effort: Balanced

    @shawkins
    shawkins enabled auto-merge (squash) November 11, 2026 14:26
    consolidated session cleanup, and changed how createOrJoinLogoutSession
    uses the userSession
    
    also adding more test coverage for orphaned state
    
    closes: keycloak#54691
    closes: CVE-2026-107124
    
    Signed-off-by: Steve Hawkins <shawkins@redhat.com>
    Copilot AI balanced review requested due to automatic review settings November 11, 2026 15:54
    Copilot AI left a comment
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🟡 Changes recommended

    The logout-root change leaves KC_AUTH_SESSION_HASH stale, causing repeated login-form reloads for up to 60 seconds when an abandoned confirmation is followed by a prompt=login request.

    1 open issue

    Review effort: Balanced

    // Never plant the id of a recovered root in the browser
    boolean recovered = logoutRoot.getId().equals(session.getAttribute(RECOVERED_LOGOUT_ROOT_ID));
    if (!recovered && (cookieRoot == null || !cookieRoot.getId().equals(logoutRoot.getId()))) {
    asm.setAuthSessionCookie(logoutRoot.getId());
    @keycloak-github-bot keycloak-github-bot Bot left a comment
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Unreported flaky test detected, please review

    @keycloak-github-bot
    Copy link
    Copy Markdown

    Unreported flaky test detected

    If the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR.

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#unauthorizedSSOTest

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
    	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
    	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
    	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
    	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
    ...
    

    Report flaky test

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#testMultipleTabsParallelLoginAfterAuthSessionExpiration

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: Expected page 'login-login' to be loaded, but currently on page 'null' after timeout
    	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
    	at org.junit.jupiter.api.Assertions.fail(Assertions.java:138)
    	at org.keycloak.testsuite.pages.AbstractPage.waitForPage(AbstractPage.java:63)
    	at org.keycloak.testsuite.pages.AbstractPage.assertCurrent(AbstractPage.java:48)
    ...
    

    Report flaky test

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#singleLoginAndLogoutSAMLTest

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: Expected page 'login-login' to be loaded, but currently on page 'null' after timeout
    	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
    	at org.junit.jupiter.api.Assertions.fail(Assertions.java:138)
    	at org.keycloak.testsuite.pages.AbstractPage.waitForPage(AbstractPage.java:63)
    	at org.keycloak.testsuite.pages.AbstractPage.assertCurrent(AbstractPage.java:48)
    ...
    

    Report flaky test

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#salesPostTestCompositeRoleForUser

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: Expected page 'login-login' to be loaded, but currently on page 'null' after timeout
    	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
    	at org.junit.jupiter.api.Assertions.fail(Assertions.java:138)
    	at org.keycloak.testsuite.pages.AbstractPage.waitForPage(AbstractPage.java:63)
    	at org.keycloak.testsuite.pages.AbstractPage.assertCurrent(AbstractPage.java:48)
    ...
    

    Report flaky test

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#salesPostEmptyConsumerPostURL

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: Expected page 'login-login' to be loaded, but currently on page 'null' after timeout
    	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
    	at org.junit.jupiter.api.Assertions.fail(Assertions.java:138)
    	at org.keycloak.testsuite.pages.AbstractPage.waitForPage(AbstractPage.java:63)
    	at org.keycloak.testsuite.pages.AbstractPage.assertCurrent(AbstractPage.java:48)
    ...
    

    Report flaky test

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#testReloginWithInvalidAuthSessionCookie

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: Expected page 'login-login' to be loaded, but currently on page 'null' after timeout
    	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
    	at org.junit.jupiter.api.Assertions.fail(Assertions.java:138)
    	at org.keycloak.testsuite.pages.AbstractPage.waitForPage(AbstractPage.java:63)
    	at org.keycloak.testsuite.pages.AbstractPage.assertCurrent(AbstractPage.java:48)
    ...
    

    Report flaky test

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#salesPostTest

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: Expected page 'login-login' to be loaded, but currently on page 'null' after timeout
    	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
    	at org.junit.jupiter.api.Assertions.fail(Assertions.java:138)
    	at org.keycloak.testsuite.pages.AbstractPage.waitForPage(AbstractPage.java:63)
    	at org.keycloak.testsuite.pages.AbstractPage.assertCurrent(AbstractPage.java:48)
    ...
    

    Report flaky test

    org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#testMultipleTabsParallelLogin

    Keycloak CI - Adapter IT

    org.opentest4j.AssertionFailedError: Expected page 'login-login' to be loaded, but currently on page 'null' after timeout
    	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
    	at org.junit.jupiter.api.Assertions.fail(Assertions.java:138)
    	at org.keycloak.testsuite.pages.AbstractPage.waitForPage(AbstractPage.java:63)
    	at org.keycloak.testsuite.pages.AbstractPage.assertCurrent(AbstractPage.java:48)
    ...
    

    Report flaky test

    @shawkins
    shawkins merged commit 59cb7ea into keycloak:main Nov 12, 2026
    107 of 116 checks passed
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    [CVE-2026-107124] Session takeover by victim logout with injected id_token_hint

    3 participants

    0