GitHub Advisoryadvisory · Packagist
GHSA-jq2f-59pj-p3m3 Craft CMS has a Missing Authorization Check on User Group Removal via save-permissions Action
MEDIUM
Official page ↗
- Aliases
- CVE-2026-41128
- Ecosystem
- Packagist
- Packages
- craftcms/cms
- Severity
- Moderate
- CVSS vector
- CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
- Weaknesses
- CWE-862
- Reviewed
- 2026-04-14
Affected packages
• Packagist craftcms/cms: >= 5.6.0, < 5.9.15 → fixed in 5.9.15
Description
Summary
The `actionSavePermissions()` endpoint allows a user with only `viewUsers` permission to remove arbitrary users from all user groups. While `_saveUserGroups()` enforces per-group authorization for additions, it performs no equivalent authorization check for removals, so submitting an empty `groups` value removes all existing group memberships.
Affected Versions
• Craft CMS 5.6.0 through 5.9.14 (latest release at time of report)
• Regression introduced in 5.6.0 when the `viewUsers` permission was added
• Prior to 5.6.0, `editedUser()` required `editUsers`, which implicitly protected this endpoint
• Requires Pro edition or higher (the vulnerable code path is gated by `CmsEdition::Pro`)
Vulnerability Details
Root Cause
This is a regression introduced in Craft CMS 5.6.0 when the `viewUsers` permission was added. Before that change, `editedUser()` required `editUsers` permission for accessing other users’ data, which implicitly protected `actionSavePermissions()`. After the change, `actionSavePermissions()` became reachable for users with read-only access to other users, but the underlying group-saving logic still lacked authorization for group removals.
The vulnerability has two components:
1. `actionSavePermissions()` reachable with read-only access: The action only requires a control panel request and delegates to `editedUser()`, which now only checks `viewUsers` — a permission explicitly documented as "read-only access to user elements."
2. Asymmetric authorization in `_saveUserGroups()`: The method checks `assignUserGroup` permission only when adding a user to a new group. When the `groups` parameter is an empty string (resulting in an empty array), the loop is skipped entirely, no authorization checks are run, and all group memberships are removed.
Prerequisites
• Attacker has a control panel account with `accessCp` and `viewUsers` permissions only
• Target user belongs to one or more user groups that grant additional permissions
• Pro edition or higher
Attack Steps
1. Attacker authenticates to the Control Panel
2. Attacker sends a POST request to `actions/users/save-permissions` with:
• `userId` = target user's ID
• `groups` = `` (empty string)
3. All group memberships for the target user are removed
4. All permissions inherited from those groups are immediately revoked
Impact
• Privilege revocation: An attacker can strip group-based permissions from arbitrary users, including accounts whose effective access derives from group membership
• Denial of access: Users lose access to sections, volumes, and features that were granted through group membership
• Bypass of elevated session requirement: Group removal does not trigger `requireElevatedSession()` (which is only triggered when new groups are added)
Related
Alias · CVE (1)
- CVE-2026-41128 Craft CMS is a content management system (CMS). vulnerability
Weakness · CWE (1)
- CWE-862 Missing Authorization weakness