Feb 10, 2026·4 min read·198 visits
Keycloak fails to check if an Identity Provider is disabled before accepting its JWTs. If an admin disables a compromised IdP but doesn't delete its keys, the attacker can still login. CVSS 8.8.
A critical logic flaw in Keycloak's implementation of JWT Authorization Grants allows disabled Identity Providers (IdPs) to continue issuing valid access tokens. By failing to check the 'enabled' status of an IdP during the resolution process, Keycloak permits attackers possessing a disabled provider's signing keys to bypass administrative restrictions and maintain unauthorized access.
Identity and Access Management (IAM) is the bouncer of your digital club. You trust it to know who's on the list and who's banned. In Keycloak, the 'Identity Provider' (IdP) toggle is supposed to be the ultimate kill switch. You suspect a partner is compromised? You flip the switch to Disabled. You go home. You sleep tight.
But in CVE-2026-1486, that switch is a lie. It’s like locking your front door but leaving the key under the mat—and telling the burglar where the mat is. This vulnerability reveals a disconnect between the administrative intent (UI configuration) and the runtime logic (token issuance). It turns out, Keycloak was perfectly happy to mint fresh access tokens for Identity Providers that were explicitly told to go away, provided they still had the right cryptographic handshake.
The vulnerability resides in how Keycloak handles the JWT Profile for OAuth 2.0 Client Authentication and Authorization Grants (RFC 7523). When Keycloak receives a JWT assertion, it needs to figure out who signed it. It looks at the iss (issuer) claim in the token and matches it against its configured Identity Providers.
Here is the logic flow in the vulnerable versions:
iss claim.IdentityProviderModel that matches this alias/issuer.IdentityProviderModel.isEnabled() is true.The code was so focused on cryptographic verification—"Does this signature match the public key we have on file?"—that it forgot the administrative verification—"Are we even supposed to be talking to this guy?" This is a classic case of valid crypto lulling developers into a false sense of security.
The fix is embarrassingly simple, which highlights just how critical the oversight was. The patch was applied primarily in FederatedJWTClientAuthenticator.java and JWTAuthorizationGrantType.java.
Let's look at the diff in FederatedJWTClientAuthenticator.java (commit 176dc89):
// THE VULNERABLE CODE
if (lookup == null || lookup.identityProviderModel() == null || lookup.clientModel() == null) {
// Error handling
}
// THE PATCHED CODE
if (lookup == null ||
lookup.identityProviderModel() == null ||
!lookup.identityProviderModel().isEnabled() || // <--- The Savior
lookup.clientModel() == null) {
// Error handling
}And similarly in JWTAuthorizationGrantType.java:
// Added explicitly before signature validation
if (!identityProviderModel.isEnabled()) {
throw new RuntimeException("Identity Provider is not enabled");
}Without these lines, the code retrieved the configuration, saw the public keys were valid, and proceeded to grant access. The isEnabled() flag was effectively a UI decoration with no backend enforcement during this specific grant flow.
Let's construct a realistic attack scenario. Imagine you are a SaaS provider using Keycloak. You have a B2B integration with ShadyCorp, set up as an Identity Provider. You give them a client_id and import their public keys so they can mint tokens for their users to access your API.
Day 1: You read news that ShadyCorp got hacked. Their private signing keys are in the wild.
Day 2: You rush to your Keycloak Admin Console. You find the ShadyCorp Identity Provider. You toggle Enabled to OFF. You breathe a sigh of relief. You assume the threat is neutralized.
Day 3: The attacker, holding ShadyCorp's private key, crafts a JWT:
{
"iss": "shady-corp-alias",
"sub": "admin-user",
"aud": "your-keycloak-realm",
"exp": 1770000000
}They sign this JWT with the stolen private key. They send it to your Keycloak token endpoint:
POST /realms/{realm}/protocol/openid-connect/token
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion={signed_jwt}
The Result: Keycloak looks up shady-corp-alias. It finds the config. It sees the public key. It verifies the signature. It ignores the fact that you disabled it. It issues a shiny new access token with full privileges. The attacker is in.
The primary fix is obviously to upgrade Keycloak. The patched versions (Red Hat build 26.4.9-1, 26.4-11, etc.) introduce the boolean checks ensuring isEnabled() is respected.
However, if you are stuck on a legacy version and cannot upgrade immediately, you must understand that disabling the provider is insufficient. To mitigate this without a patch, you must perform a 'cryptographic lobotomy':
If Keycloak cannot verify the signature (because the key is gone), the exploit fails, regardless of the logic bug.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Red Hat build of Keycloak Red Hat | 26.4.x < 26.4.9 | 26.4.9-1 |
Keycloak Keycloak | < Commit 176dc89 | PR #46148 |
| Attribute | Detail |
|---|---|
| CWE | CWE-287 |
| CVSS v3.1 | 8.8 (High) |
| Attack Vector | Network |
| EPSS Score | 0.00045 |
| Impact | Authorization Bypass |
| Exploit Status | PoC Available (Logic Trivial) |
| Patch Status | Available |
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.