The Keycloak Upgrade Ledger

Every upgrade we have rehearsed, with the environment stated and the clock running.

2026-09-06 · run 2026-09-06-cve-2026-16105-composite-endpoint-authz

CVE-2026-16105: name-based composite endpoints now enforce per-role authorization

Condition
CVE-2026-16105 (a delegated manage-realm admin could add/remove child roles from built-in admin roles via the name-based composite endpoint

Question

Does 26.7.3 enforce the CVE-2026-16105 fix — i.e. do the name-based composite endpoints (/roles/{role-name}/composites and /clients/{client-uuid}/roles/{role-name}/composites) now call auth.roles().requireManage(role) like the id-based (/roles-by-id/{role-id}/composites) endpoints always did?

Method

Same FGAP-v2 fixture realm (fgap-cves), but the delegated admin is granted manage-realm (realm-management client role) instead of remaining a view-only admin — this is the "delegated administrator with manage-realm permissions" the advisory names.

Target: the realm-management client's realm-admin composite role (a built-in admin role — the class the CVE is about). Pick one of its child roles and attempt to remove it through the name-based endpoint.

Then, as the delegated admin:

Result

CallResponse
DELETE .../roles/realm-admin/composites (name-based)HTTP 403
child role still a composite of realm-admin (read back as master admin)True — unchanged

Target child in this run: manage-organizations (first composite returned; the choice is immaterial — the guard is per-role, not per-child).

Finding

26.7.3 rejects the composite edit with 403 and leaves the role unchanged. The fix adds auth.roles().requireManage(role) to both addComposites and deleteComposites in RoleContainerResource (the name-based path). The id-based RoleByIdResource path already had this check — the vulnerability was that the two paths had drifted.

Primary source: commit 81ada68d956b3b412741c5c8e9dbefacc3410cf9 "Missing per-role authorization on RoleContainerResource composite endpoints" (closes #51002).

Verification

ClaimPrimary sourceChecked
addComposites gains requireManage(role)commit 81ada68d diff, RoleContainerResource.java
deleteComposites gains requireManage(role)commit 81ada68d diff, RoleContainerResource.java
Id-based path already guarded (drift, not absence)RoleByIdResource.java addComposites/deleteComposites call requireManage
Name-based delete now rejected for delegated adminlive DELETE .../roles/realm-admin/composites → 403
Composite unchanged after the attemptlive read-back: child still present

← Back to the Ledger