Skip to content

fix(security): prevent privilege escalation through team settings - #654

Merged
mckenziearts merged 2 commits into
2.xfrom
fix/team-settings-privilege-escalation
Aug 14, 2026
Merged

fix(security): prevent privilege escalation through team settings#654
mckenziearts merged 2 commits into
2.xfrom
fix/team-settings-privilege-escalation

Conversation

@mckenziearts

Copy link
Copy Markdown
Collaborator

Problem

Settings/Team write actions are gated on access_setting, the general purpose settings permission granted to anyone who configures currencies, taxes, zones or legal pages. It carries no relationship to user or role management, yet holding it was enough to take over the RBAC system.

A non administrator holding it could:

  • create a permission with any name through createPermission, which immediately assigns it to the role being edited
  • generate the five CRUD permissions for any resource through generatePermissions and receive them all
  • open RolePermission for the administrator role itself, since the route binds {role} with no scoping, and update or delete it
  • toggle any existing permission onto their own role through Permissions::togglePermission()
  • create a team member and assign them the administrator role through CreateTeamMember, since the role options only excluded the customer role

The net effect is that every permission in the panel collapsed into access_setting. Granting it to let someone configure shipping also granted them a path to full administrator capability. This reproduces the impact of CVE-2026-47744, whose published fix describes a manage_users permission that has never existed in the source tree.

Permissions::removePermission() had a second, unrelated defect: the can_be_removed guard existed only in the Blade view. A crafted Livewire request could delete access_setting or access_dashboard and lock every user out of the panel.

Fix

No new permission, no migration, nothing to run on upgrade. The gates stay on view_users for reads and access_setting for writes. What changes is what a non administrator may do once inside.

Three rules, in Shopper\Traits\AuthorizesTeamManagement:

Rule Effect
A non administrator cannot target the administrator role it can no longer be opened, updated, deleted, or assigned to a new team member
A permission can only be granted if the acting user holds it granting yourself an unrelated capability is no longer possible
Creating or deleting a permission definition is administrator only inventing a permission to bypass the rule above is no longer possible

Administrators are unaffected: they hold every permission and every rule short circuits for them.

removePermission() now checks can_be_removed on the server before deleting.

The seeder description for access_setting said the permission only allowed viewing the settings page. It has never matched what the permission gates, and that mismatch is what made the original report read the situation as a read only permission guarding writes.

Behaviour change

A non administrator who was creating permissions or editing the administrator role through access_setting loses that ability. Everything else they could do in the settings area is unchanged, and no existing permission assignment is modified.

Dependencies

The first commit carries the composer update -W from the same session. The Filament floor moves from ^4.11 to ^4.12 on the admin package so installs are guaranteed the form and table rendering optimizations shipped in v4.12.0. spatie/laravel-medialibrary moves to ^11.23.3 for the single file collection fix that affects the thumbnail collection, and livewire/blaze to ^1.0.14 for conditional slots being rendered unconditionally.

Raise the Filament floor to ^4.12 on the admin package so installs always
get the form and table rendering optimizations shipped in v4.12.0, which
^4.11 did not guarantee.

Two patch level floors are required rather than cosmetic:

- spatie/laravel-medialibrary ^11.23.3 fixes a single file collection
  dropping the media that was just added instead of the previous one.
  Shopper declares singleFile on the thumbnail collection.
- livewire/blaze ^1.0.14 fixes conditional slots being rendered even when
  their condition is false.

The remaining bumps align the floor with the installed minor version.
Any user holding access_setting could reach every write action on the team
settings and leave with more privileges than they came in with: mint a new
permission, self assign it, grant themselves permissions over unrelated
resources, edit the administrator role, or create a new administrator
account. Every other permission in the panel collapsed into that single
one.

The gates stay on view_users and access_setting. What changes is what a non
administrator is allowed to do once inside:

- the administrator role can no longer be opened, updated, deleted, or
  assigned to a new team member
- a permission can only be granted to a role if the acting user holds that
  permission themselves
- creating or deleting a permission definition is restricted to
  administrators

removePermission now honours can_be_removed on the server. The guard only
existed in the Blade view, so a crafted request could delete a permission
the panel depends on and lock everyone out.

The access_setting seeder description said the permission only allowed
viewing the settings page, which never matched what it gates.
@mckenziearts mckenziearts added this to the v2 milestone Aug 8, 2026
@mckenziearts mckenziearts added bug Something isn't working security php Pull requests that update php code labels Aug 8, 2026
@mckenziearts mckenziearts self-assigned this Aug 11, 2026
@mckenziearts
mckenziearts merged commit 11b180f into 2.x Aug 14, 2026
68 checks passed
@mckenziearts
mckenziearts deleted the fix/team-settings-privilege-escalation branch August 14, 2026 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working php Pull requests that update php code security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant