CVE-2026-97177: Keycloak Delegated Admin Account Takeover

Guilliano Molaire Guilliano Molaire 9 min read

Last updated: September 2026

CVE-2026-97177 is a Keycloak flaw where a delegated administrator who has been explicitly denied the reset-password permission can still set a user’s password, by sending it inside an ordinary user update request to the Admin REST API. It only matters in realms that use Fine-Grained Admin Permissions (FGAP) to separate “manage this user” from “reset this user’s password”, but where you do, that separation does not hold and the result is account takeover. Red Hat published it on 24 September 2026 with a CVSS 3.1 base score of 6.6, and no fixed Keycloak release exists yet.

The reporter credited in the CVE record is Paul Bottinelli of Trail of Bits, working in collaboration with OpenAI, who also reported the sibling flaw CVE-2026-94001 in the credential delete endpoint five days earlier. Both come down to the same thing: two Admin REST endpoints that change a user’s credentials check the broad “manage” permission instead of the specific “reset-password” one.

What does CVE-2026-97177 break?

It breaks the reset-password boundary in Fine-Grained Admin Permissions. In the CVE record Red Hat published on 24 September 2026, the flaw is described as the user update mechanism failing “to check for specific password reset authorizations during a general user profile update,” which lets a restricted delegated administrator “change a user’s credentials and take over their account” (CVE Program, CVE-2026-97177 record, 2026).

Reset-password denial versus generic user update

FGAP, the second version of Keycloak’s fine-grained admin permissions, lets you grant an administrator rights over some users instead of the whole realm, using scopes on the Users resource type. Two of those scopes matter here. manage covers editing a user’s details, and reset-password covers changing their password. The split is deliberate: a helpdesk or tenant admin who corrects names and email addresses does not necessarily need the power to set a password, because whoever sets a password can log in as that user.

Keycloak honours that split on the dedicated endpoint. PUT /admin/realms/{realm}/users/{id}/reset-password calls auth.users().requireResetPassword(user) before touching anything, so an administrator whose reset-password permission evaluates to deny gets a 403.

Why the generic update path becomes account takeover

The general update endpoint, PUT /admin/realms/{realm}/users/{id}, is the one the Admin REST API documents as “Update the user”. In the current Keycloak source, UserResource.updateUser checks only auth.users().requireManage(user), then applies the request body and passes it to RepresentationToModel.createCredentials. That method walks the credentials array in the body and, for any entry with a value, writes it as the user’s password:

if (cred.getValue() != null && !cred.getValue().isEmpty()) {
    ...
    user.credentialManager().updateCredential(UserCredentialModel.password(cred.getValue(), false));

So an administrator with manage on a user can send a body like this and the password changes, whatever the reset-password permission says:

{
  "credentials": [
    { "type": "password", "value": "attacker-chosen", "temporary": false }
  ]
}

Setting temporary to false matters to an attacker, because a temporary password adds the Update Password required action and would force a change at next login. With it false, the delegated admin can log in as the user immediately. The realm’s password policy still applies, which constrains the password chosen but does not stop the takeover.

The same file shows how the check was meant to work. The endpoint that only renames a credential’s label, PUT .../credentials/{credentialId}/userLabel, does call requireResetPassword. Changing a label needs the specific permission, while changing the password itself through the generic update does not.

The sibling flaw: CVE-2026-94001

CVE-2026-94001, published on 19 September 2026, is the same gap on DELETE /admin/realms/{realm}/users/{id}/credentials/{credentialId}, which also checks only requireManage. There the impact is a denial of access rather than a takeover: a delegated admin denied reset-password can delete a user’s password credential so they cannot log in. Red Hat rates it CVSS 6.5 with high integrity and availability impact. Treat the two as one audit, because they share both the precondition and the mitigation.

Which Keycloak realms are exposed?

You are exposed only if a realm uses FGAP and gives some administrator manage on users while denying them reset-password. Red Hat’s vector is CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H, classified CWE-862 Missing Authorization. High privileges required is accurate, because the attacker is an administrator, but that is precisely the person FGAP is meant to constrain.

The realm has Admin Permissions enabled. FGAP is switched on per realm, with the Admin Permissions switch under Realm settings, after which a Permissions section appears in the admin console menu. Realms that manage administrators only with the built-in realm-management roles are not affected, because those roles do not separate the two actions.

The reset-password scope exists in your version. In our reading of the Keycloak release tags, the reset-password scope on the Users resource type first appears in 26.4.0. It is not in 26.2.0 or 26.3.0, so on those lines there was no separate permission to bypass.

Someone holds manage without reset-password. In UserPermissionsV2.canResetPassword, an administrator holding the manage-users role always passes, and otherwise Keycloak evaluates the reset-password scope, falling back to the manage decision only when no permission covers reset-password at all. The case that breaks is a permission that grants manage alongside one that explicitly denies reset-password, which is the typical helpdesk or tenant-admin design.

The legacy V1 fine-grained permissions are a different story. V1 never had a separate reset-password decision, since canResetPassword there defaults to canManage. There is nothing to bypass, but also no way to express the restriction in the first place.

If you use Organizations to give each customer tenant its own administrators, this is the configuration most likely to carry the split. Our guide to multitenancy with the Organizations feature covers that setup, and our write-up of CVE-2026-16072 and CVE-2026-18201 covers two earlier permission gaps in the same area.

How do I find the administrators this affects?

Find every FGAP permission that denies reset-password, then list the administrators who also hold manage over the same users. In the admin console, FGAP permissions live under Permissions in a realm with Admin Permissions enabled. Filter for the Users resource type and look for permissions whose scopes include reset-password and whose policy is negative, or whose decision strategy denies a subset of administrators.

For each administrator or group those permissions name, check whether another permission grants them manage on the same users or groups. Every administrator who ends up with manage and a denied reset-password can currently change passwords despite the denial.

What should I do before a fix ships?

Stop relying on the reset-password denial as a security boundary, and remove manage from anyone who must not be able to set passwords. As of 25 September 2026, the CVE record names no fixed version, Red Hat states that no mitigation meets its criteria, and the newest community releases on each maintained line (26.7.4, 26.6.7 and 26.4.16) predate the disclosure.

Take manage away from reset-restricted admins. If an administrator must not change passwords, the only reliable control right now is that they cannot update the user at all. Give them view on users plus the narrower scopes they actually need, such as manage-group-membership or map-roles, and route profile edits to someone who is trusted with passwords anyway.

Accept that the audit trail will not show the password change. Keycloak records a generic update as an admin event with operation UPDATE on users/{id}. Even with Include representation turned on, StripSecretsUtils.stripUser sets the representation’s credentials to null before storage, so the logged event does not show that a password was set. A proper reset through the dedicated endpoint records an ACTION on the reset-password resource path instead. To look for past abuse, correlate UPDATE events on users performed by reset-restricted administrators with that user’s subsequent LOGIN events from unfamiliar addresses. Our Keycloak auditing and event logging guide covers turning on and exporting both event types.

Filter the request at the edge if you cannot restructure permissions. A proxy in front of the admin API can reject every PUT to /admin/realms/{realm}/users/{id} whose JSON body contains a non-empty credentials array, which pushes all password changes through the dedicated reset-password endpoint where the permission is enforced. Exempting your full administrators from that rule needs a gateway that can read the roles in the caller’s bearer token, which a plain reverse proxy cannot do. Test the rule against your own tooling first, since any automation that sets passwords through the update call will break.

Plan to upgrade to the fixed release on your own line. Fixes do not only go to the newest minor version: Keycloak shipped 26.4.15 and 26.6.6 on 11 August 2026, weeks after 26.7.0, so a 26.4 or 26.6 realm can expect a patch on its own line. Watch those release notes for CVE-2026-97177 and CVE-2026-94001. If you run the Red Hat build of Keycloak, follow Red Hat’s advisory for the product version that carries the fix.

For the endpoints themselves and how to script against them, see our Keycloak Admin REST API guide.

How is this different from other Keycloak account takeover CVEs?

CVE-2026-97177 needs an authenticated administrator, which puts it in a different class from the unauthenticated takeovers. CVE-2026-18963, for example, was a password reset takeover that an outside attacker could reach. This one is an insider or compromised-admin problem, closer in shape to CVE-2026-17526, where impersonation let a limited administrator act with more power than they were granted.

The pattern across these delegated-admin CVEs is consistent. FGAP adds a new, narrower permission, and every Admin REST endpoint that can achieve the same effect needs to check it. Endpoints that predate the narrower permission tend to keep checking the broad one. When you design a delegated admin role, it is worth asking which other endpoints can reach the same outcome as the one you restricted, and testing those too.

What does managed Keycloak change here?

Running Keycloak as a managed service moves the patching work, but the permission model stays yours. On Skycloak, identity management as a service built on upstream Keycloak, we roll security releases onto customer clusters, so the fix for CVE-2026-97177 lands without you scheduling an upgrade. Which administrators hold manage, and whether a reset-password denial is carrying weight in your design, are realm decisions you own, and the audit above applies equally to a managed realm.

Frequently asked questions

Can an unauthenticated attacker exploit CVE-2026-97177?

No. The attacker must be a Keycloak administrator with the FGAP manage permission on the target user. Red Hat’s CVSS vector sets privileges required to High. The risk is a delegated admin, or a compromised delegated admin account, exceeding the rights you meant to give them, which is the case FGAP exists to control.

Which Keycloak versions are affected by CVE-2026-97177?

The CVE record from 24 September 2026 lists the Red Hat build of Keycloak without version ranges and Red Hat Single Sign-On 7 as unaffected. In the community source, the reset-password scope that this bypasses first appears in 26.4.0, and the update endpoint checks only manage in 26.4.16, 26.6.7 and 26.7.4 alike. Test your own build.

Does the admin console expose this, or only the API?

The flaw is in the Admin REST API, which the admin console also uses. Any administrator with manage on a user can send the request directly with their own admin token, so hiding a button in the console is not a mitigation. The server-side permission check is the only one that counts.

Will admin events show that a password was changed?

Not directly. The update is logged as operation UPDATE on users/{id}, and Keycloak strips credentials from the stored representation, so the event does not reveal the password change. Correlating those updates with the user’s later logins is the practical way to spot misuse.

What is CVE-2026-94001?

It is the companion flaw published on 19 September 2026: the credential delete endpoint also checks only manage, so a delegated admin denied reset-password can delete a user’s password credential and lock them out. Red Hat rates it CVSS 6.5. The same mitigation, removing manage from reset-restricted admins, covers both.

Sources

  • CVE Program, “CVE-2026-97177: generic user update bypasses denied reset-password permission”, CNA record from Red Hat, published 24 September 2026, retrieved 2026-09-25, https://www.cve.org/CVERecord?id=CVE-2026-97177 (record JSON: https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/97xxx/CVE-2026-97177.json)
  • CVE Program, “CVE-2026-94001: admin credential delete bypasses denied reset-password permission”, CNA record from Red Hat, published 19 September 2026, retrieved 2026-09-25, https://www.cve.org/CVERecord?id=CVE-2026-94001
  • Red Hat Customer Portal, “CVE-2026-97177”, https://access.redhat.com/security/cve/CVE-2026-97177 (linked from the CVE record; not reachable from our research environment)
  • Red Hat Bugzilla, bug 2539965, https://bugzilla.redhat.com/show_bug.cgi?id=2539965
  • Keycloak, UserResource.java, keycloak/keycloak on GitHub, retrieved 2026-09-25, https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
  • Keycloak, UserPermissionsV2.java, keycloak/keycloak on GitHub, retrieved 2026-09-25, https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/services/resources/admin/fgap/UserPermissionsV2.java
  • Keycloak, RepresentationToModel.java, keycloak/keycloak on GitHub, retrieved 2026-09-25, https://github.com/keycloak/keycloak/blob/main/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
  • Keycloak, AdminPermissionsSchema.java, keycloak/keycloak on GitHub, retrieved 2026-09-25, https://github.com/keycloak/keycloak/blob/main/server-spi-private/src/main/java/org/keycloak/authorization/fgap/AdminPermissionsSchema.java
  • Keycloak releases, tags 26.7.4, 26.6.7 and 26.4.16, retrieved 2026-09-25, https://github.com/keycloak/keycloak/releases

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