Skip to content

[CVE-2026-16105] Missing per-role authorization on RoleContainerResou…#51084

Open
martin-kanis wants to merge 1 commit into
keycloak:mainfrom
martin-kanis:issue-51002
Open

[CVE-2026-16105] Missing per-role authorization on RoleContainerResou…#51084
martin-kanis wants to merge 1 commit into
keycloak:mainfrom
martin-kanis:issue-51002

Conversation

@martin-kanis

Copy link
Copy Markdown
Contributor

…rce composite endpoints

Closes #51002

…rce composite endpoints

Closes keycloak#51002

Signed-off-by: Martin Kanis <mkanis@ibm.com>
Copilot AI review requested due to automatic review settings July 22, 2026 09:31
@martin-kanis
martin-kanis requested a review from a team as a code owner July 22, 2026 09:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds per-role authorization to name-based composite role endpoints, addressing CVE-2026-16105.

Changes:

  • Requires manage permission on the target role when adding or deleting composites.
  • Adds integration tests confirming unauthorized operations return forbidden without modifying composites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java Enforces target-role manage authorization.
tests/base/src/test/java/org/keycloak/tests/admin/authz/rbac/InternalClientManagementTest.java Covers unauthorized composite additions and removals.

@sguilhen

Copy link
Copy Markdown
Contributor

Hi @martin-kanis! The fix looks good overall, I just noticed something that might be worth handling now or at least as a follow up. The same container-only auth pattern also exists on the GET side. The name-based read endpoints in RoleContainerResource check requireView(roleContainer) but not requireView(role) - see getRoleComposites, getRealmRoleComposites, and getClientRoleComposites.

Their ID-based equivalents in RoleByIdResource all check requireView(role). I think we should follow the same pattern and add auth.roles().requireView(role) after the role lookup. Do you think we should also handle this as part of this PR or do you prefer to keep it focused and we address the GET side on a follow up?

@vramik
vramik self-requested a review July 23, 2026 09:06
@vramik

vramik commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR. Before we proceed, I want to share some analysis of what this change actually does under both RBAC and FGAP evaluation, because I think we need to align on whether this addresses a real security boundary.

No view or manage scopes exist for roles in FGAP

The Roles resource type in AdminPermissionsSchema only defines three scopes: map-role, map-role-client-scope, and map-role-composite. There is no view or manage scope. This means under FGAP, requireView(role) and requireManage(role) have no per-resource scope to evaluate — they cannot provide any finer-grained check than the container-level calls. Should these scopes be added in the future, the PR would become meaningful as defense-in-depth.

Under classic RBAC, requireView(role) is equivalent to requireView(roleContainer)

canView(RoleModel role) delegates directly to the container:

  • Realm role → canViewRealm() → requires view-realm
  • Client role → canView(client) → requires view-clients

This is identical to canView(RoleContainerModel). So @sguilhen's suggestion to add requireView(role) to the GET endpoints would have no effect under either authorization model today. Again probably meaningful defense-in-depth addition.

Under classic RBAC, requireManage(role) differs from requireManage(roleContainer) only by the isRealmAdminRole guard

canManage(RoleModel role) for realm roles checks canManageRealm() && !isRealmAdminRole(role), while canManage(RoleContainerModel) checks only canManageRealm(). The sole difference is the isRealmAdminRole guard. This is what the PR relies on — a manage-realm holder would be blocked from modifying composites on the built-in admin role.

However, manage-realm is effectively equivalent to realm-admin (still to be implemented)

So the reported scenario (a manage-realm delegate stripping composites from the admin role) is not a real privilege boundary violation — the attacker already has equivalent power.

The PR is valid as defense-in-depth and for consistency with RoleByIdResource, so +1 for having it, but it does not fix a real exploitable vulnerability.

I would like to hear some thoughts, how would you like to proceed with it. For instance, we can merge it and adjust when we are merging the two roles, not sure what to do with the CVE though.

@sguilhen

Copy link
Copy Markdown
Contributor

@vramik do you think this should have not been assigned a CVE?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CVE-2026-16105] Missing per-role authorization on RoleContainerResource composite endpoints

4 participants