Feb 10, 2026·4 min read·153 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 |
netfoil, an allowlist-based DNS proxy, failed to sanitize ALPN fields parsed from untrusted DNS-over-HTTPS (DoH) HTTPS Resource Records. This allowed attackers to inject ANSI escape sequences into log files or trigger Denial of Service (DoS) via uncontrolled memory allocations.
An issue was discovered in the tokio-postgres library for Rust prior to version 0.7.18. A trust assumption mismatch between the PostgreSQL protocol messages sent by a server and how they are parsed and indexed by the client-side library allows a rogue or compromised database server to trigger a Denial of Service (DoS) crash via an unhandled out-of-bounds slice indexing panic.
CVE-2026-14669 is a critical heap-based buffer overflow vulnerability in PostgreSQL's date/time formatting function to_char(timestamptz). The flaw arises from unsafe copying of user-controlled timezone abbreviations into a fixed-size internal buffer. An authenticated database user can trigger this issue by setting a long POSIX timezone abbreviation containing custom formatting, allowing them to overwrite adjacent heap structures and hijack execution control to achieve remote code execution (RCE) with the privileges of the 'postgres' operating system user.
An unauthenticated remote denial of service vulnerability exists in the Unleash feature management platform. By submitting a crafted JSON payload containing deeply nested structures to an OpenAPI-validated endpoint, an attacker can trigger uncontrolled recursion within the error formatting module. This leads to a call-stack exhaustion (RangeError: Maximum call stack size exceeded) inside the Node.js runtime, causing the service to crash immediately without recovery.
CVE-2026-63004 is a server-side request forgery (SSRF) vulnerability in the Unleash feature management platform. Authenticated administrators with CREATE_ADDON or UPDATE_ADDON privileges can exploit this vulnerability to initiate requests to loopback addresses, private networks, and cloud metadata endpoints, potentially leading to information disclosure and credential extraction.
Prior to version 8.0.3, Unleash's Markdown event formatter directly mutated the global template-escaping function of the shared mustache Node.js module, resulting in a process-wide security degradation where HTML/Markdown escaping was permanently disabled for the application lifetime.