Skip to content

FGAP V2: isInternal denylist missing admin-permissions client allows delegated admin to update it #51630

Closed

Description

@abstractj

Description

ClientPermissions.isInternal denylists only the realm-management client (and, in the master realm, client IDs ending in the -realm suffix). The admin-permissions client — the resource server holding the realm's entire FGAP V2 model — is not in that list.

As a result, a delegated administrator holding a FGAP Clients:manage permission (and no realm-management roles) can update and disable the admin-permissions client through the Admin API. The API's own access report (getAccess) correctly returns manage: false for this client, but the enforcement path in canManage does not agree — it falls through to the FGAP permission check and allows the write.

This is a gap in the isInternal denylist introduced in 26.7.0. No privilege escalation results from this — FGAP enforcement resolves the client by internal ID, not by clientId, and disabling the client does not relax the delegated admin's own restrictions.

Version affected

26.7.0 and main. The isInternal guard was introduced in 26.7.0; 26.6.x has a different code path and is not affected.

Expected behavior

The admin-permissions client should be treated as internal, consistent with realm-management. A delegated admin with Clients:manage should not be able to update or disable it. The enforcement path and the access report should agree.

Actual behavior

  • isInternal returns false for the admin-permissions client
  • canManage falls through to the FGAP permission check, which grants access via Clients:manage
  • getAccess returns manage: false (it special-cases this client), contradicting enforcement
  • The delegated admin can set serviceAccountsEnabled, add redirect URIs, enable directAccessGrantsEnabled, and rename clientId
  • Deleting the client is correctly refused (HTTP 400)

Steps to reproduce

  1. Start Keycloak 26.7.0 with default features (FGAP V2 enabled by default).
  2. In a realm, enable adminPermissionsEnabled (FGAP V2 configuration).
  3. Create a delegated admin user with a FGAP Clients:manage permission but no realm-management roles.
  4. As the delegated admin, GET /admin/realms/{realm}/clients/{admin-permissions-client-id} — note access.manage = false.
  5. As the delegated admin, PUT /admin/realms/{realm}/clients/{admin-permissions-client-id} with a modified body (e.g., add a redirect URI) — observe HTTP 204 success.
  6. As the master admin, verify the change persisted.

Root cause

ClientPermissions.isInternal (line 719) checks only for realm-management and -realm suffix clients. Constants.ADMIN_PERMISSIONS_CLIENT_ID is missing from the predicate. The getAccess method at line 676 correctly special-cases this client, but canManage at line 63 does not mirror the same check.

Suggested fix

Add Constants.ADMIN_PERMISSIONS_CLIENT_ID to ClientPermissions.isInternal. This is the smallest change and matches how realm-management is already handled.

Acknowledgement

Mahdi Alhakim (GitHub: mahdi-al-hakim)


This issue was originally tracked in the private repository. Migrated by @abstractj.

Activity

  1. added theissue type on Aug 11, 2026
  2. added a commit that references this issue on Aug 12, 2026
    074b7df
  3. self-assigned this
    on Oct 9, 2026
  4. 4 remaining items

  5. added a commit that references this issue on Oct 14, 2026
    c104900
  6. added 3 commits that reference this issue on Oct 14, 2026
    139fc8d
    a2f0dc8
    57db624
  7. added a commit that references this issue on Oct 15, 2026
    46b8d96
  8. added 2 commits that reference this issue on Oct 22, 2026
    c6d2987
    d8841f8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Fields

No fields configured for bug.

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions