{"id":"CVE-2026-56828","aliases":["EUVD-2026-112148","GHSA-j328-xmgp-j4q3"],"status":"published","title":"Shopper: read-only team permissions allow administrator creation and permission escalation","description":"Shopper is a Headless e-commerce Admin Panel. From 2.8.0 until 2.8.1, three Shopper Livewire admin components retain authorization gaps after the earlier team-settings authorization fix. A staff member with only `view_users` and `access_dashboard` can mutate permissions, create an administrator, or delete roles. In `packages/admin/src/Livewire/Components/Settings/Team/Permissions.php`, `togglePermission` and `removePermission` authorize `view_users` rather than the stronger `access_setting` permission; `packages/admin/resources/views/livewire/components/settings/team/permissions.blade.php` exposes permission IDs in `wire:click` handlers. The attacker can grant arbitrary permissions to the bound role, including `access_setting` on the attacker's own role, or delete permission definitions. In `packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php`, `mount()` and `store()` also accept `view_users`, and the client-selected `role_id` can identify the admin role, allowing creation of a pre-verified administrator with an attacker-chosen password. In `packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php`, `deleteAction` has no action authorization and is only conditioned on `can_be_removed`, while page access requires `view_users`. Deleting a removable role removes access for assigned users, enabling RBAC denial of service as well as privilege escalation. This issue is fixed in version 2.8.1.","severity":{"version":"3.1","score":8.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00441,"percentile":0.38755,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-285","CWE-862"],"published":"2026-09-11T21:28:54Z","modified":"2026-11-03T13:17:22Z","fixes":[{"ecosystem":"Packagist","package":"shopper/framework","fixed_in":["2.9.2"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"shopper/framework","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.8.0"},{"fixed":"2.9.2"}]}]},{"source":"osv","ecosystem":"Packagist","package":"shopper/framework","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.8.0"},{"fixed":"2.9.2"}]}],"versions":["v2.8.0","v2.8.1","v2.9.0","v2.9.1"]}],"products":[{"vendor":"shopperdotcom","product":"shopper"},{"vendor":"shopperlabs","product":"shopper"}],"references":[{"url":"https://github.com/shopperlabs/shopper/security/advisories/GHSA-j328-xmgp-j4q3","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/shopperlabs/shopper/pull/514","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/shopperlabs/shopper/commit/ac9a76044a8e4a2b570b438d66cf3007f3dc479e","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/shopperlabs/shopper/compare/v2.8.1...v2.9.2","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/shopperlabs/shopper/releases/tag/v2.8.1","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-j328-xmgp-j4q3"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/56xxx/CVE-2026-56828.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-56828","tags":["advisory"]},{"url":"https://github.com/shopperlabs/shopper","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-56828","title":"Shopper: read-only team permissions allow administrator creation and permission escalation","description":"Shopper is a Headless e-commerce Admin Panel. From 2.8.0 until 2.8.1, three Shopper Livewire admin components retain authorization gaps after the earlier team-settings authorization fix. A staff member with only `view_users` and `access_dashboard` can mutate permissions, create an administrator, or delete roles. In `packages/admin/src/Livewire/Components/Settings/Team/Permissions.php`, `togglePermission` and `removePermission` authorize `view_users` rather than the stronger `access_setting` permission; `packages/admin/resources/views/livewire/components/settings/team/permissions.blade.php` exposes permission IDs in `wire:click` handlers. The attacker can grant arbitrary permissions to the bound role, including `access_setting` on the attacker's own role, or delete permission definitions. In `packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php`, `mount()` and `store()` also accept `view_users`, and the client-selected `role_id` can identify the admin role, allowing creation of a pre-verified administrator with an attacker-chosen password. In `packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php`, `deleteAction` has no action authorization and is only conditioned on `can_be_removed`, while page access requires `view_users`. Deleting a removable role removes access for assigned users, enabling RBAC denial of service as well as privilege escalation. This issue is fixed in version 2.8.1.","status":"published","published":"2026-10-28T15:40:39.294Z","modified":"2026-11-03T13:06:24.272Z","cvss":[{"version":"3.1","score":8.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-285","CWE-862"],"updated_at":"2026-11-03T14:28:05.368159Z"}],"euvd":[{"id":"EUVD-2026-112148","description":"Shopper is a Headless e-commerce Admin Panel. From 2.8.0 until 2.8.1, three Shopper Livewire admin components retain authorization gaps after the earlier team-settings authorization fix. A staff member with only `view_users` and `access_dashboard` can mutate permissions, create an administrator, or delete roles. In `packages/admin/src/Livewire/Components/Settings/Team/Permissions.php`, `togglePermission` and `removePermission` authorize `view_users` rather than the stronger `access_setting` permission; `packages/admin/resources/views/livewire/components/settings/team/permissions.blade.php` exposes permission IDs in `wire:click` handlers. The attacker can grant arbitrary permissions to the bound role, including `access_setting` on the attacker's own role, or delete permission definitions. In `packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php`, `mount()` and `store()` also accept `view_users`, and the client-selected `role_id` can identify the admin role, allowing creation of a pre-verified administrator with an attacker-chosen password. In `packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php`, `deleteAction` has no action authorization and is only conditioned on `can_be_removed`, while page access requires `view_users`. Deleting a removable role removes access for assigned users, enabling RBAC denial of service as well as privilege escalation. This issue is fixed in version 2.8.1.","status":"published","published":"2026-10-28T15:40:39Z","modified":"2026-11-03T13:06:24Z","cvss":[{"version":"3.1","score":8.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-03T15:18:10.516363Z"}],"ghsa":[{"id":"GHSA-j328-xmgp-j4q3","title":"Shopper: privilege escalation via improper Livewire admin component authorization","description":"## Summary\n\nThree Livewire admin components in `shopper/framework` (latest master at commit `fcd0c59`, released as v2.8.0) gate state-mutating actions on the read-only `view_users` permission. This is the same class as the issue Shopper fixed in v2.8.0 / PR #511 / [GHSA-f946-9qp6-vgch](https://github.com/shopperlabs/shopper/security/advisories/GHSA-f946-9qp6-vgch) — the PR moved most write actions from `view_users` to `access_setting`, but three were missed (one of them is a brand-new file added by the security commit itself).\n\nA staff user holding only `view_users` + `access_dashboard` (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 `can_be_removed=true` — delete entire roles.\n\nCVSS 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).\n\n## Vulnerable components (paths relative to repo root)\n\n### 1) `packages/admin/src/Livewire/Components/Settings/Team/Permissions.php`\n\n- `togglePermission(int $id)` at line 28 calls `$this-\u003eauthorize('view_users');`\n- `removePermission(int $id)` at line 55 calls `$this-\u003eauthorize('view_users');`\n\nThe 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.\n\nNet effect: any user who can mount the Permissions component (gated on `view_users`) can grant any permission row to the bound `$role`. Granting `access_setting` to the attacker's own role unlocks every action that PR #511 supposedly hardened with `-\u003eauthorize('access_setting')`. Granting `delete_customers`, `edit_orders`, `edit_products`, `add_brands`, etc. is direct data-modification escalation.\n\n### 2) `packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php`\n\n- `mount()` at line 53 calls `$this-\u003eauthorize('view_users');`\n- `store()` at line 122 calls `$this-\u003eauthorize('view_users');`\n\nThis file is `new file mode 100755` in commit `fcd0c59` — it was created as part of the security fix and inherited the same misclassified gate.\n\n`store()` creates a `User` with `email_verified_at = now()`, the attacker's chosen password, and any selected `role_id`. The `Radio::make('role_id')` 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.\n\n### 3) `packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php`\n\n- `deleteAction` at lines 81-90: only gated by `-\u003evisible($this-\u003erole-\u003ecan_be_removed)`, with no `-\u003eauthorize()` chain.\n\nPage-level `mount` (line 52) requires only `view_users`. For any role with `can_be_removed = true`, a `view_users`-only user can call the action and delete the role (cascading the loss of permissions for every assigned user).\n\n## Self-confirmation in the project's own test suite\n\nThe following tests are green on master @ `fcd0c59` — they ARE the PoC:\n\n```\ntests/Admin/Livewire/Components/Settings/Team/PermissionsTest.php\n  line 14-16: `givePermissionTo('view_users')` only\n  line 36-45: \"can toggle permission to role\" — passes\n  line 74-85: \"can remove permission\" — passes\n\ntests/Admin/Livewire/SlideOvers/CreateTeamMemberTest.php\n  line 16-18: `givePermissionTo('view_users')` only\n  line 29-56: \"can create new team member\" — passes, asserts the new user `hasRole('manager')`\n```\n\nA `view_users`-only Livewire user actor successfully toggles permissions, removes permissions, and creates a new privileged user — verified by Shopper's own regression tests.\n\n## Suggested fix\n\nChange `$this-\u003eauthorize('view_users')` to `$this-\u003eauthorize('access_setting')` in:\n\n- `Permissions::togglePermission`\n- `Permissions::removePermission`\n- `Permissions::mount` (defence in depth, matches `Team\\Index`)\n- `CreateTeamMember::mount`\n- `CreateTeamMember::store`\n\nAdd `-\u003eauthorize('access_setting')` to `RolePermission::deleteAction` (matches the pattern already applied to `generatePermissionsAction`, `createPermissionAction`, and `Team\\Index::DeleteAction`).\n\nUpdate the two regression tests to use `access_setting` instead of `view_users` so they accurately reflect the privilege boundary.\n\n## Resources\n\n- Prior advisory of the same class: https://github.com/shopperlabs/shopper/security/advisories/GHSA-f946-9qp6-vgch\n- Fix commit that introduced these residual gaps: https://github.com/shopperlabs/shopper/commit/fcd0c5920588702df5b874f432b1042abd77a50b\n- CWE-285 Improper Authorization\n- CWE-862 Missing Authorization\n\n### Credits\n\nReported by Vishal Shukla(@shukla304) using sechub.dev AI Agent\n\n### Support\n\nIf 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.","status":"published","published":"2026-09-11T21:28:54Z","modified":"2026-09-11T21:28:54Z","cvss":[{"version":"3.1","score":8.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-285","CWE-862"],"updated_at":"2026-11-02T14:41:15.803194Z"}],"nvd":[{"id":"CVE-2026-56828","description":"Shopper is a Headless e-commerce Admin Panel. From 2.8.0 until 2.8.1, three Shopper Livewire admin components retain authorization gaps after the earlier team-settings authorization fix. A staff member with only `view_users` and `access_dashboard` can mutate permissions, create an administrator, or delete roles. In `packages/admin/src/Livewire/Components/Settings/Team/Permissions.php`, `togglePermission` and `removePermission` authorize `view_users` rather than the stronger `access_setting` permission; `packages/admin/resources/views/livewire/components/settings/team/permissions.blade.php` exposes permission IDs in `wire:click` handlers. The attacker can grant arbitrary permissions to the bound role, including `access_setting` on the attacker's own role, or delete permission definitions. In `packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php`, `mount()` and `store()` also accept `view_users`, and the client-selected `role_id` can identify the admin role, allowing creation of a pre-verified administrator with an attacker-chosen password. In `packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php`, `deleteAction` has no action authorization and is only conditioned on `can_be_removed`, while page access requires `view_users`. Deleting a removable role removes access for assigned users, enabling RBAC denial of service as well as privilege escalation. This issue is fixed in version 2.8.1.","status":"published","published":"2026-10-28T16:17:08.22Z","modified":"2026-11-04T23:10:00.223Z","cvss":[{"version":"3.1","score":8.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-285","CWE-862"],"updated_at":"2026-11-05T01:45:13.243042Z"}],"osv":[{"id":"CVE-2026-56828","title":"Shopper: read-only team permissions allow administrator creation and permission escalation","description":"Shopper is a Headless e-commerce Admin Panel. From 2.8.0 until 2.8.1, three Shopper Livewire admin components retain authorization gaps after the earlier team-settings authorization fix. A staff member with only `view_users` and `access_dashboard` can mutate permissions, create an administrator, or delete roles. In `packages/admin/src/Livewire/Components/Settings/Team/Permissions.php`, `togglePermission` and `removePermission` authorize `view_users` rather than the stronger `access_setting` permission; `packages/admin/resources/views/livewire/components/settings/team/permissions.blade.php` exposes permission IDs in `wire:click` handlers. The attacker can grant arbitrary permissions to the bound role, including `access_setting` on the attacker's own role, or delete permission definitions. In `packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php`, `mount()` and `store()` also accept `view_users`, and the client-selected `role_id` can identify the admin role, allowing creation of a pre-verified administrator with an attacker-chosen password. In `packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php`, `deleteAction` has no action authorization and is only conditioned on `can_be_removed`, while page access requires `view_users`. Deleting a removable role removes access for assigned users, enabling RBAC denial of service as well as privilege escalation. This issue is fixed in version 2.8.1.","status":"published","published":"2026-10-28T15:40:39.294Z","modified":"2026-11-05T21:16:07.497663229Z","cvss":[{"version":"3.1","score":8.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-285","CWE-862"],"updated_at":"2026-11-05T22:00:58.054534Z"},{"id":"GHSA-j328-xmgp-j4q3","title":"Shopper: privilege escalation via improper Livewire admin component authorization","description":"## Summary\n\nThree Livewire admin components in `shopper/framework` (latest master at commit `fcd0c59`, released as v2.8.0) gate state-mutating actions on the read-only `view_users` permission. This is the same class as the issue Shopper fixed in v2.8.0 / PR #511 / [GHSA-f946-9qp6-vgch](https://github.com/shopperlabs/shopper/security/advisories/GHSA-f946-9qp6-vgch) — the PR moved most write actions from `view_users` to `access_setting`, but three were missed (one of them is a brand-new file added by the security commit itself).\n\nA staff user holding only `view_users` + `access_dashboard` (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 `can_be_removed=true` — delete entire roles.\n\nCVSS 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).\n\n## Vulnerable components (paths relative to repo root)\n\n### 1) `packages/admin/src/Livewire/Components/Settings/Team/Permissions.php`\n\n- `togglePermission(int $id)` at line 28 calls `$this-\u003eauthorize('view_users');`\n- `removePermission(int $id)` at line 55 calls `$this-\u003eauthorize('view_users');`\n\nThe 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.\n\nNet effect: any user who can mount the Permissions component (gated on `view_users`) can grant any permission row to the bound `$role`. Granting `access_setting` to the attacker's own role unlocks every action that PR #511 supposedly hardened with `-\u003eauthorize('access_setting')`. Granting `delete_customers`, `edit_orders`, `edit_products`, `add_brands`, etc. is direct data-modification escalation.\n\n### 2) `packages/admin/src/Livewire/SlideOvers/CreateTeamMember.php`\n\n- `mount()` at line 53 calls `$this-\u003eauthorize('view_users');`\n- `store()` at line 122 calls `$this-\u003eauthorize('view_users');`\n\nThis file is `new file mode 100755` in commit `fcd0c59` — it was created as part of the security fix and inherited the same misclassified gate.\n\n`store()` creates a `User` with `email_verified_at = now()`, the attacker's chosen password, and any selected `role_id`. The `Radio::make('role_id')` 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.\n\n### 3) `packages/admin/src/Livewire/Pages/Settings/Team/RolePermission.php`\n\n- `deleteAction` at lines 81-90: only gated by `-\u003evisible($this-\u003erole-\u003ecan_be_removed)`, with no `-\u003eauthorize()` chain.\n\nPage-level `mount` (line 52) requires only `view_users`. For any role with `can_be_removed = true`, a `view_users`-only user can call the action and delete the role (cascading the loss of permissions for every assigned user).\n\n## Self-confirmation in the project's own test suite\n\nThe following tests are green on master @ `fcd0c59` — they ARE the PoC:\n\n```\ntests/Admin/Livewire/Components/Settings/Team/PermissionsTest.php\n  line 14-16: `givePermissionTo('view_users')` only\n  line 36-45: \"can toggle permission to role\" — passes\n  line 74-85: \"can remove permission\" — passes\n\ntests/Admin/Livewire/SlideOvers/CreateTeamMemberTest.php\n  line 16-18: `givePermissionTo('view_users')` only\n  line 29-56: \"can create new team member\" — passes, asserts the new user `hasRole('manager')`\n```\n\nA `view_users`-only Livewire user actor successfully toggles permissions, removes permissions, and creates a new privileged user — verified by Shopper's own regression tests.\n\n## Suggested fix\n\nChange `$this-\u003eauthorize('view_users')` to `$this-\u003eauthorize('access_setting')` in:\n\n- `Permissions::togglePermission`\n- `Permissions::removePermission`\n- `Permissions::mount` (defence in depth, matches `Team\\Index`)\n- `CreateTeamMember::mount`\n- `CreateTeamMember::store`\n\nAdd `-\u003eauthorize('access_setting')` to `RolePermission::deleteAction` (matches the pattern already applied to `generatePermissionsAction`, `createPermissionAction`, and `Team\\Index::DeleteAction`).\n\nUpdate the two regression tests to use `access_setting` instead of `view_users` so they accurately reflect the privilege boundary.\n\n## Resources\n\n- Prior advisory of the same class: https://github.com/shopperlabs/shopper/security/advisories/GHSA-f946-9qp6-vgch\n- Fix commit that introduced these residual gaps: https://github.com/shopperlabs/shopper/commit/fcd0c5920588702df5b874f432b1042abd77a50b\n- CWE-285 Improper Authorization\n- CWE-862 Missing Authorization\n\n### Credits\n\nReported by Vishal Shukla(@shukla304) using sechub.dev AI Agent\n\n### Support\n\nIf 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.","status":"published","published":"2026-09-11T21:28:54Z","modified":"2026-09-11T21:45:09.88822294Z","cvss":[{"version":"3.1","score":8.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-285","CWE-862"],"updated_at":"2026-11-02T15:46:49.977351Z"}]}}
