Skip to content

Prevent privilege escalation when assigning roles via /authz/roles - #27154

Draft
dennisoelkers wants to merge 1 commit into
masterfrom
security/guard-privilege-escalation-in-authz-roles-resource
Draft

Prevent privilege escalation when assigning roles via /authz/roles#27154
dennisoelkers wants to merge 1 commit into
masterfrom
security/guard-privilege-escalation-in-authz-roles-resource

Conversation

@dennisoelkers

@dennisoelkers dennisoelkers commented Aug 28, 2026

Copy link
Copy Markdown
Member

Note: This needs a backport to 7.1, 7.0 & 6.3.

Description

Motivation and Context

PUT /authz/roles/{roleId}/assignees assigned a role to a user without
checking that the caller holds the permissions that role grants. Holding
users:rolesedit on the target user plus roles:assign on the role was
enough to grant permissions the caller does not have themselves - for
example adding somebody (or oneself) to a role carrying *.

RolesResource and UsersResource already run requested permissions
through PrivilegeEscalationGuard; this closes the equivalent gap on the
remaining role-assignment endpoint.

Un-assigning stays unguarded: removing a role reduces privileges, and
gating it would stop a less privileged administrator from demoting an
over-privileged user. Since addUser and removeUser share
updateUserRole, the check is switched by an explicit parameter.

How Has This Been Tested?

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have requested a documentation update.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.

`PUT /authz/roles/{roleId}/assignees` assigned a role to a user without
checking that the caller holds the permissions that role grants. Holding
`users:rolesedit` on the target user plus `roles:assign` on the role was
enough to grant permissions the caller does not have themselves - for
example adding somebody (or oneself) to a role carrying `*`.

`RolesResource` and `UsersResource` already run requested permissions
through `PrivilegeEscalationGuard`; this closes the equivalent gap on the
remaining role-assignment endpoint.

Un-assigning stays unguarded: removing a role reduces privileges, and
gating it would stop a less privileged administrator from demoting an
over-privileged user. Since `addUser` and `removeUser` share
`updateUserRole`, the check is switched by an explicit parameter.

Verified by mutation: dropping the `validatePermissions` call fails 3 of
the 4 new tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant