Keycloak CIBA Lockout Fix: Brute-Force Check Added to Token Redemption

Guilliano Molaire Guilliano Molaire 7 min read

Keycloak 26.7.5 (30 September 2026) closed an incomplete fix in Client Initiated Backchannel Authentication (CIBA). Brute-force protection had been added when a CIBA request is started, but the handler that redeems an approved request for tokens did not check whether the user had since been locked out. A client holding valid confidential-client credentials could therefore redeem a request that was started and approved before the lockout and still receive access and refresh tokens for that user. The fix adds the brute-force check to the token redemption step, and it is present in 26.7.5, 26.8.0 and later.

This applies only if you use CIBA with confidential clients and have brute-force detection turned on. If you do not run CIBA, this path is not part of your exposure. The rest of this post explains the flaw, how to tell whether it affects you, how to look for signs of misuse, and what to upgrade to.

Key takeaways

  • The brute-force check exists in BackchannelAuthenticationEndpoint (request initiation) in 26.7.4. The same check appears in CibaGrantType (token redemption) from 26.7.5.
  • Releases before 26.7.5 that I checked, 26.7.4, 26.6.7 and 26.4.16, have no brute-force check in CibaGrantType.
  • Exposure requires CIBA, a confidential client with valid credentials, and an approved request that was redeemed after the lockout.
  • Upgrade to 26.7.5 or later on the 26.7 line, or to 26.8.0 or later.

What is CIBA, briefly?

CIBA lets an application ask the identity provider to authenticate a user on a different device, with no browser redirect on the device making the request. A call-center system, a bank teller application or a smart speaker sends a backchannel authentication request naming the user. The provider asks the user to approve it on their phone, and the application then polls the token endpoint (or receives a ping or push notification) and collects the tokens once the user has approved. For setup details, see our guide to CIBA in Keycloak.

What is brute-force lockout supposed to guarantee?

Keycloak’s brute-force detection temporarily or permanently disables a user after too many failed logins. The expectation is that while an account is locked, it cannot complete a new login or grant. Existing refresh tokens are a separate matter, because the refresh grant checks only whether the user is enabled. Earlier CIBA work enforced this when a CIBA request starts: if the target user is locked, the backchannel authentication endpoint refuses the request.

What was the gap?

A CIBA request has two moments that matter: when it is started, and when it is redeemed. The user’s state can change between those two moments. A user may approve the request on their phone, and then be locked out because of failed password attempts from another source before the client collects the tokens.

In 26.7.4 the redemption code in CibaGrantType checked that the user exists and is enabled, but it did not call the brute-force check. I compared the source of 26.7.4 and 26.7.5 (linked above): the 26.7.5 version adds a call to AuthenticatorUtils.getDisabledByBruteForceEventError and returns an invalid_grant error (“User disabled”) if the user is locked. The 26.8.0 source contains the same check.

This is the follow-up to an earlier fix that covered initiation only, which is why it is described as an incomplete fix. Check the Keycloak security advisories for a CVE identifier and severity rating, because this post is based on a comparison of the source and not on an advisory.

The impact is narrower than it first sounds. Manually disabling the user was already enforced at redemption, because 26.7.4 checks that the user is enabled. What the gap bypassed was the temporary brute-force lockout. A permanent lockout disables the user, which 26.7.4 already checked, so the practical effect is a pending approval that survives a temporary lockout and can be collected later, within the request’s lifetime.

Am I affected?

You need all of the following:

  1. CIBA is enabled for at least one client (the client has the CIBA grant on its settings).
  2. The client is confidential, meaning it authenticates to the token endpoint with a secret or a key. An attacker needs valid client credentials to redeem a request, which is what limits the exposure.
  3. Brute-force detection is on in the realm. If it is off, no lockout exists for the redemption step to ignore.
  4. You are on a release without the fix: anything before 26.7.5 on the 26.7 line, or an older minor line that has not received a backport.

That last point matters for 26.6 and 26.4. When this was written, the latest releases on those lines, 26.6.7 and 26.4.16, had no brute-force check in CibaGrantType. Keycloak does release patches for older minor lines, so look for a newer 26.6 or 26.4 point release and confirm it includes the change before treating the line as safe. We have not seen a fix on lines older than 26.4, so from those the safe path is upgrading.

How do I look for misuse?

Keycloak’s event log is the place to look. Enable user events if you have not, then search for token grants after a lockout for the same user:

  • Find users who were locked by brute-force detection. Keycloak records a USER_DISABLED_BY_TEMPORARY_LOCKOUT event (or USER_DISABLED_BY_PERMANENT_LOCKOUT) when it locks an account, usually after a run of LOGIN_ERROR events with invalid_user_credentials. You can also check the user’s brute-force status in the admin console. If user events were not enabled before, you cannot search the past, so turn them on now for future detection.
  • For those users, look at AUTHREQID_TO_TOKEN events (the event type for CIBA token requests) whose timestamps fall after the lockout. Refresh token events after a lockout are not evidence of this issue on their own, because refresh tokens issued earlier keep working during a temporary lockout.
  • Pay special attention to CIBA token grants that follow a long gap after the original authentication request was approved.

Because redemption requires a request that was approved by the real user first, you are looking for a narrow case: a legitimate approval followed by a lockout and then a token grant. Treat any such event as worth a second look. Our auditing and event logging guide shows how to configure the events you need.

How do I patch?

For self-hosted deployments:

  1. Upgrade to 26.7.5 or later if you are on the 26.7 line, or 26.8.0 or later.
  2. After upgrading, test the behavior: start a CIBA request for a test user and approve it through your authentication channel. Then trigger enough failed password logins to lock the user, and redeem the auth_req_id before the request expires (the realm’s CIBA policy sets this, 120 seconds by default, so you may want to raise it temporarily for the test). The token endpoint should return invalid_grant with “User disabled”, and the event log should show AUTHREQID_TO_TOKEN_ERROR with user_temporarily_disabled.
  3. Shorten the lifetime of CIBA authentication requests in the realm’s CIBA policy to what your use case needs, which narrows the window between approval and redemption.
  4. Keep brute-force protection enabled and review the thresholds. Our post on the IP-based brute-force protection gap explains a limit of the feature that is worth knowing about.

If you are coming from a release older than 26.7.4, the upgrade also picks up the fixes in our 26.7.4 patch checklist. Also see the post on device flow lockout (CVE-2026-88770), a related case on a different grant type. For the wider context on token protection, see NIST IR 8587 and Keycloak.

On Skycloak we apply upstream Keycloak security releases, so managed instances move to a release with this fix without action from you.

Frequently asked questions

What is the CIBA lockout vulnerability in Keycloak?

It is a gap where brute-force lockout was enforced when a CIBA request started but not when the approved request was redeemed for tokens. A client with valid confidential credentials could redeem a request approved before the lockout and receive tokens for a locked user. Keycloak 26.7.5 adds the check to the redemption step.

Which Keycloak versions fix it?

26.7.5, 26.8.0 and 26.8.1 contain the brute-force check in the CIBA token redemption code. 26.7.4, 26.6.7 and 26.4.16 do not. Check the release notes of any 26.6 or 26.4 point release before assuming it is fixed.

Do I need to worry if I do not use CIBA?

No. The affected code path runs only for CIBA token requests. You should still upgrade for the other fixes in the same release.

Can an attacker exploit this without credentials?

No. Redeeming a CIBA request requires authenticating as the confidential client that started it, and the real user must have approved the request first. The risk is a compromised or malicious client credential combined with a lockout that happens after approval.

What does the fix return for a locked user?

The token endpoint returns an invalid_grant error with the description “User disabled”, and the event log records an AUTHREQID_TO_TOKEN_ERROR event with error user_temporarily_disabled (a permanently locked user is disabled, so it gets user_disabled, as it did before the fix).

Is CIBA safe to use in production?

Yes, with normal care. Use confidential clients, short request lifetimes, binding messages that tell the user what they are approving, and brute-force protection, and keep Keycloak on a patched release.

Patched on the day, not on your next maintenance window

Keycloak 26.7.2 fixed CVE-2026-18963, an account takeover through password reset. Skycloak had it available for auto-upgrade and told customers the same day upstream shipped it. Self-hosted teams schedule that work themselves.

Guilliano Molaire
Written by
Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Start Free Trial Talk to Sales
© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman