Coordinated Disclosure Timeline
- 2026-02-25: The report was sent.
- 2026-02-26: The issue was acknowledged as a collision with another reporter.
- 2026-03-10: Fixed in Umbraco CMS 16.5.1 and 17.2.2. The matching vendor advisory is GHSA-rhcg-3h8r-v6vp / CVE-2026-31834.
Summary
Umbraco CMS is vulnerable to an authorization bypass issue (GHSL-2026-065) that allows unauthorized users to assign users to groups, potentially leading to privilege escalation and improper access control.
Project
Tested Version
Details
Missing Authorization Check for Group Assignment (GHSL-2026-065)
The UpdateUserGroupsUserController.UpdateUserGroups method performs the following authorization check:
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
User,
UserPermissionResource.WithKeys(requestModel.UserIds.Select(x => x.Id)),
AuthorizationPolicies.UserPermissionByResource);
Missing Validation:
The authorization check validates whether the current user can modify the TARGET users, but it does NOT validate whether the current user can assign the specified USER GROUPS.
Comparison with UpdateUserController:
The single-user update endpoint (UpdateUserController) includes proper group assignment validation via UserEditorAuthorizationHelper.IsAuthorized (called in UserService), which checks:
- Non-admin users can only assign groups they themselves belong to (
UserEditorAuthorizationHelper) - Start node permissions
- Other security constraints
However, UpdateUserGroupsUserController bypasses this validation entirely and calls UserGroupService.UpdateUserGroupsOnUsersAsync directly, which only validates that the admin group won’t become empty (UserGroupService) but does NOT check which groups can be assigned.
Attack Scenario:
- Attacker Profile: Authenticated backoffice API user with
SectionAccessUserspermission (access to Users section), but NOT an admin. It looks like the only group with access to Users section by default isAdministrators, but Umbraco allows creation of custom new groups. - Target: The attacker’s own API user account (or another non-API non-admin user).
- Attack Steps:
POST /umbraco/management/api/v1/user/set-user-groups HTTP/1.1 Authorization: Bearer <attacker's token> Content-Type: application/json { "userIds": [ { "id": "<target's user GUID>" } ], "userGroupIds": [ { "id": "<admin group GUID>" }, { "id": "<other groups...>" } ] }The admin group GUID is a well-known constant:
Constants.Security.AdminGroupKey, but also can be retrieved byGET/umbraco/management/api/v1/user-groupAPI call. User GUID can be retrieved byGET/umbraco/management/api/v1/userAPI call. - Result: Attacker’s account is added to the admin group. Note that for non-API user with the same permissions is allowed to change some user properties, but it is not allowed to perform the group assignment, i.e. it is correctly restricted.
Impact
This issue allows authenticated non-admin API users to gain admin privileges.
CWEs
- CWE-284: “Improper Access Control”
Credit
This issue was discovered with the GitHub Security Lab Taskflow Agent and manually verified by GHSL team member @JarLob (Jaroslav Lobačevski).
Contact
You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2026-065 in any communication regarding this issue.