CVE-2026-56828: High severity composer/shopper/framework vulnerability

Published Sep 11, 2026
·
Updated

Summary

Three Livewire admin components in shopper/framework (latest master at commit fcd0c59, released as v2.8.0) gate state-mutating actions on the read-only viewusers permission. This is the same class as the issue Shopper fixed in v2.8.0 / PR #511 / GHSA-f946-9qp6-vgch — the PR moved most write actions from viewusers to accesssetting, but three were missed (one of them is a brand-new file added by the security commit itself).

A staff user holding only viewusers + accessdashboard (a realistic "support" or "viewer" role per Shopper's own PermissionsTableSeeder) can: (1) self-escalate by granting any permission to their own role; (2) create a brand-new admin team member with a chosen password and the admin role and then log in as that user; (3) delete arbitrary permissions rows (RBAC DoS) or — when canberemoved=true — delete entire roles.

CVSS 3.1: AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H = 8.8 (High). CWE-285 (Improper Authorization) + CWE-862 (Missing Authorization).

Vulnerable components (paths relative to repo root)

1) packages/admin/src/Livewire/Components/Settings/Team/Permissions.php

- togglePermission(int $id) at line 28 calls $this->authorize('viewusers'); - removePermission(int $id) at line 55 calls $this->authorize('viewusers');

The Permissions blade at packages/admin/resources/views/livewire/components/settings/team/permissions.blade.php line 34 emits every permission's id directly in wire:click handlers, so the attacker does not even need to guess IDs — the page itself enumerates them.

Net effect: any user who can mount the Permissions component (gated on viewusers) can grant any permission row to the bound $role. Granting accesssetting to the attacker's own role unlocks every action that PR #511 supposedly hardened with ->authorize('accesssetting'). Granting deletecustomers, editorders, editproducts, addbrands, etc. is direct data-modification escalation.

2) packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php

- mount() at line 53 calls $this->authorize('viewusers'); - store() at line 122 calls $this->authorize('viewusers');

This file is new file mode 100755 in commit fcd0c59 — it was created as part of the security fix and inherited the same misclassified gate.

store() creates a User with emailverifiedat = now(), the attacker's chosen password, and any selected roleid. The Radio::make('roleid') options filter only excludes config('shopper.admin.roles.user'), so the admin role is selectable. Log out, log in as the new account → full admin.

3) packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php

- deleteAction at lines 81-90: only gated by ->visible($this->role->canberemoved), with no ->authorize() chain.

Page-level mount (line 52) requires only viewusers. For any role with canberemoved = true, a viewusers-only user can call the action and delete the role (cascading the loss of permissions for every assigned user).

Self-confirmation in the project's own test suite

The following tests are green on master @ fcd0c59 — they ARE the PoC:

tests/Admin/Livewire/Components/Settings/Team/PermissionsTest.php line 14-16: givePermissionTo('viewusers') only line 36-45: "can toggle permission to role" — passes line 74-85: "can remove permission" — passes

tests/Admin/Livewire/SlideOvers/CreateTeamMemberTest.php line 16-18: givePermissionTo('viewusers') only line 29-56: "can create new team member" — passes, asserts the new user hasRole('manager')

A viewusers-only Livewire user actor successfully toggles permissions, removes permissions, and creates a new privileged user — verified by Shopper's own regression tests.

Suggested fix

Change $this->authorize('viewusers') to $this->authorize('accesssetting') in:

- Permissions::togglePermission - Permissions::removePermission - Permissions::mount (defence in depth, matches Team\Index) - CreateTeamMember::mount - CreateTeamMember::store

Add ->authorize('accesssetting') to RolePermission::deleteAction (matches the pattern already applied to generatePermissionsAction, createPermissionAction, and Team\Index::DeleteAction).

Update the two regression tests to use accesssetting instead of viewusers so they accurately reflect the privilege boundary.

Resources

- Prior advisory of the same class: https://github.com/shopperlabs/shopper/security/advisories/GHSA-f946-9qp6-vgch - Fix commit that introduced these residual gaps: https://github.com/shopperlabs/shopper/commit/fcd0c5920588702df5b874f432b1042abd77a50b - CWE-285 Improper Authorization - CWE-862 Missing Authorization

Credits

Reported by Vishal Shukla(@shukla304) using sechub.dev AI Agent

Support

If this disclosure was useful and if users would like to support continued open-source security research and responsible-disclosure work, they can sponsor at https://github.com/sponsors/therawdev — Shoppers thanks those who keeping open source safe.

Affected Software

1 affected componentFixes available
composer/shopper/framework>=2.8.0<2.9.2
2.9.2

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade composer/shopper/framework to a version that resolves this vulnerability.

    Fixed in 2.9.2
  2. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in v2.8.0
  3. Configuration

    In RolePermission::deleteAction, add/replace the authorization so the action is gated by access_setting (the current code is described as only gated by visible($this->role->can_be_removed) with no authorize chain).

    Shopper Admin Livewire - packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php (RolePermission::deleteAction) authorize('access_setting') added = $this->authorize('access_setting')
  4. Configuration

    Change the RolePermission page-level authorization used by the component/mount (described as mount line 52 calling $this->authorize('view_users')) to $this->authorize('access_setting').

    Shopper Admin Livewire - packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php $this->authorize('view_users') -> $this->authorize('access_setting') = access_setting
  5. Configuration

    For the Livewire component described as Permissions::mount, Permissions::removePermission, and Permissions::togglePermission, replace authorization checks of $this->authorize('view_users') with $this->authorize('access_setting') so only users with access_setting can mutate permissions/roles.

    Shopper Admin Livewire - packages/admin/src/Livewire/Components/Settings/Team/Permissions.php Authorization for state-mutating methods (mount/removePermission/togglePermission) = access_setting
  6. Configuration

    Change CreateTeamMember::mount (described as calling $this->authorize('view_users') at line 53) and CreateTeamMember::store (described as calling $this->authorize('view_users') at line 122) to $this->authorize('access_setting') so view_users-only users cannot create privileged team members.

    Shopper Admin Livewire - packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php Authorization for store/mount = access_setting
  7. Operational

    Update the regression tests (tests/Admin/Livewire/Components/Settings/Team/PermissionsTest.php and tests/Admin/Livewire/SlideOvers/CreateTeamMemberTest.php) to use access_setting instead of view_users so they correctly reflect the intended privilege boundary.

Event History

Sep 11, 2026
Advisory Published
via GitHub·09:28 PM
Data Sourced
via GitHub·09:28 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Which users should be treated as able to exploit this issue?

Any authenticated staff user assigned both view_users and access_dashboard is exposed, even if they have no broader administrative permissions. This matches realistic support or viewer-style roles described by the PermissionsTableSeeder.

2

What level of access does an attacker need?

The attacker needs a valid low-privilege staff account with view_users and access_dashboard. No user interaction is required after authentication, and the issue can be exploited remotely through the affected admin functionality.

3

What can be done if a fix cannot be deployed immediately?

Do not assign the combination of view_users and access_dashboard to untrusted or low-privilege staff accounts until the affected authorization checks are corrected. Review existing support and viewer roles for that permission combination.

4

How can an organization assess potential impact from an existing account?

Review whether accounts with view_users and access_dashboard could have modified permissions or roles, created administrative team members, or deleted permission records. Role deletion is possible where the affected role has can_be_removed=true.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203