Uploaded image for project: 'Red Hat build of Keycloak'
  1. Red Hat build of Keycloak
  2. RHBK-3483

Unbounded login_hint Parameter Can Corrupt KC_RESTART Cookie and Break Login Flow [GHI#40857]

XMLWordPrintable

    • False
    • Hide

      None

      Show
      None
    • False

      Before reporting an issue

      [x] I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

      Area

      oidc

      Describe the bug

      The optional login_hint parameter in the OIDC login URL is accepted without any size validation. When supplied with a long value, it is:

      • Reflected into the email/username field on the login form
      • Stored in the authentication session
      • Serialized into the KC_RESTART cookie

      If the resulting cookie exceeds the ~4096-byte browser limit, it is dropped or truncated by the browser. This breaks the login flow, resulting in:

      • Blank 0-byte responses
      • Intermittent redirect loops
      • In some cases, HTTP 502 errors

      This leads to unstable authentication behavior and increased backend load. The issue reflects uncontrolled input handling in a core login path, affecting reliability and availability.

      Version

      Observed in multiple real-world deployments Keycloak v17+. Issue is present in latest source code as of June 2025.

      Regression

      [ ] The issue is a regression

      Expected behavior

      The optional login_hint parameter should have a reasonable length limit and be validated before:

      • Being reflected into the login form (e.g., email/username field).
      • Being stored in the authentication session via.
      • Being serialized into the KC_RESTART cookie.

      This would prevent cookie overflow, preserve session integrity, and ensure stable login behavior.

      Actual behavior

      The optional login_hint parameter is accepted and processed without size validation. When a long value is supplied:

      • It is reflected directly into the login form's email field.
      • It is stored in session notes and serialized into the KC_RESTART cookie.
      • The resulting KC_RESTART cookie can exceed the ~4096-byte browser limit.

      When the cookie becomes oversized:

      • The browser silently drops or truncates it.
      • Keycloak cannot resume the session.
      • This results in broken login behavior such as:
      • Blank 0-byte HTTP responses
      • Occasional redirect loops
      • HTTP 502 errors in some environments

      !Image
      Screenshot from a real-world deployment demonstrating the KC_RESTART cookie exceeding 4096 bytes(environment details redacted)

      How to Reproduce?

      1. Set up a default Keycloak instance (17+), using standard OIDC login flow.

      2. Create a login URL with a very long login_hint value, such as:
      https://<keycloak-domain>/realms/<realm-name>/protocol/openid-connect/auth?login_hint=AAAA...AAAA (e.g., 4000+ characters)&client_id=your-client-id&response_type=code&scope=openid&redirect_uri=https://your-app.com/callback

      3. Visit the URL in a [browser.]

      4. Observe:

      • The long login_hint appears in the email/username field on the login page.
      • In browser console and dev tools, the KC_RESTART cookie is large or near the 4096-byte limit.

      Anything else?

      Technical References (login_hint Flow)

      All of the following paths and snippets are taken directly from Keycloak’s source code (main). They show how the optional login_hint parameter propagates without size checks.

      Parameter Definition
      File: OIDCLoginProtocol.java
      Path: services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
      Link: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java

      public static final String LOGIN_HINT_PARAM = "login_hint";

      > No length or format checks when reading this optional parameter.

      Reflected in the Login Form
      File: FreeMarkerLoginFormsProvider.java
      Path: services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java
      Link: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java

      login.username = escape(kcContext.getLoginHint());

      > No validation or size limit before reflecting user input into the UI (even though escaped).

      Stored in Session Notes
      File: AuthorizationEndpoint.java
      Path: services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
      Link: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java

      authSession.setClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint);

      > setClientNote(...) accepts any length; no bounds or format checks before adding to session.

      Session Note Interface
      File: AuthenticationSessionModel.java (JavaDoc)
      Link: https://www.keycloak.org/docs-api/latest/javadocs/org/keycloak/sessions/AuthenticationSessionModel.html

      void setClientNote(String name, String value);
      String getClientNote(String name);
      

      > No maximum length or sanitization of client notes—allows unbounded session data.

      Serialized into the KC_RESTART Cookie
      File: RestartLoginCookie.java
      Path: services/src/main/java/org/keycloak/protocol/oidc/utils/RestartLoginCookie.java
      Link: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/protocol/oidc/utils/RestartLoginCookie.java

      for (Map.Entry<String, String> entry : authSession.getClientNotes().entrySet()) {
      

      notes.put(entry.getKey(), entry.getValue());

      }
      String encoded = encodeAndEncrypt(session, restart);
      session.getProvider(CookieProvider.class).set(CookieType.AUTH_RESTART, encoded);
      

      > No check on total cookie size (e.g., the 4096‑byte browser limit) before setting it.

      Summary of Missing Validations

      • No input length limits on login_hint anywhere.
      • No format or sanitization checks before reflecting, storing, or serializing the value.
      • No aggregate cookie size enforcement, leading to session corruption and broken login flows.

      This behavior has been observed across three real-world Keycloak deployments during responsible bug bounty testing. The issue has been confirmed directly from Keycloak's source code, and it affects both the latest and previous versions using the default OIDC login flow.

              Unassigned Unassigned
              pvlha Pavel Vlha
              Keycloak Core Clients
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated:
                Resolved: