Every CVE Search/ Get API key

CVE-2026-56826

Shopper: Missing function-level authorization on Settings tax/zone/shipping Livewire components allows a low-privileged user to delete commerce configuration

5.4 MediumFix available

Shopper is a Headless e-commerce Admin Panel. From 2.0.0 until 2.9.2, authenticated users who could reach the Settings pages with only access_setting could directly invoke destructive actions through the Livewire endpoint because packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php, packages/admin/src/Livewire/Components/Settings/Zones/Detail.php, packages/admin/src/Livewire/Components/Settings/Taxes/Detail.php, and packages/admin/src/Livewire/Components/Settings/Taxes/TaxRates.php did not enforce server-side delete authorization. The actions could delete carrier options, shipping zones, tax zones, and tax rates, disrupting checkout shipping, payment-method mapping, and tax calculation. This issue is fixed in version 2.9.2.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
Low
Availability
Low

Exploit likelihood

0.34%Up 0.1 points since Oct 14, 2026
90%50%10%1%

What each source reports

CVE List Score used 5.4

Shopper: Missing function-level authorization on Settings tax/zone/shipping Livewire components allows a low-privileged user to delete commerce configuration

Shopper is a Headless e-commerce Admin Panel. From 2.0.0 until 2.9.2, authenticated users who could reach the Settings pages with only access_setting could directly invoke destructive actions through the Livewire endpoint because packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php, packages/admin/src/Livewire/Components/Settings/Zones/Detail.php, packages/admin/src/Livewire/Components/Settings/Taxes/Detail.php, and packages/admin/src/Livewire/Components/Settings/Taxes/TaxRates.php did not enforce server-side delete authorization. The actions could delete carrier options, shipping zones, tax zones, and tax rates, disrupting checkout shipping, payment-method mapping, and tax calculation. This issue is fixed in version 2.9.2.

Record
CVE-2026-56826
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-862
Updated
2026-11-02
EUVDEUVD-2026-100520 5.4

Shopper is a Headless e-commerce Admin Panel. From 2.0.0 until 2.9.2, authenticated users who could reach the Settings pages with only access_setting could directly invoke destructive actions through the Livewire endpoint because packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php, packages/admin/src/Livewire/Components/Settings/Zones/Detail.php, packages/admin/src/Livewire/Components/Settings/Taxes/Detail.php, and packages/admin/src/Livewire/Components/Settings/Taxes/TaxRates.php did not enforce server-side delete authorization. The actions could delete carrier options, shipping zones, tax zones, and tax rates, disrupting checkout shipping, payment-method mapping, and tax calculation. This issue is fixed in version 2.9.2.

Record
EUVD-2026-100520
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Updated
2026-11-02
GitHub AdvisoriesGHSA-f7h9-qv4x-9x57 5.4

Shopping privilege escalation through missing authorization in Settings components

Summary

Four Livewire components in the Settings area expose destructive Filament actions (delete / edit) that perform no server-side authorization. Any authenticated user who can reach the Settings pages — i.e. holding only the coarse access_setting permission, without being an admin and without any delete_*/edit_* permission — can delete tax zones, tax rates, shipping zones, and carrier (shipping-rate) options by invoking the component action directly over the Livewire endpoint.

These records sit on the storefront checkout path, so deleting them breaks shipping-rate calculation, removes region-scoped payment methods, and corrupts tax resolution at checkout.

This is inconsistent with the rest of the admin, where destructive actions are gated by granular permissions (e.g. Settings/Locations/Index uses ->authorize('delete_inventories'), and Order/Detail gates mutating actions with edit_orders).

Affected components

| Component | File | Unauthorized action | |---|---|---| | Settings\Zones\ZoneShippingOptions | packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php:47 | delete → CarrierOption::query()->find($arguments['id'])->delete() (id is client-supplied) | | Settings\Zones\Detail | packages/admin/src/Livewire/Components/Settings/Zones/Detail.php:46 | delete → DeleteAction on the bound Zone | | Settings\Taxes\Detail | packages/admin/src/Livewire/Components/Settings/Taxes/Detail.php:42 | delete → DeleteAction on the bound TaxZone | | Settings\Taxes\TaxRates | packages/admin/src/Livewire/Components/Settings/Taxes/TaxRates.php:97 | delete → DeleteAction on a TaxRate |

Each file contains zero authorize calls, and the actions declare neither ->authorize() nor an enforced ->visible() guard.

Details

The Settings pages mount these as child Livewire components. The parent page authorizes access_setting (e.g. Pages/Settings/Taxes.php:29), but the child components do not re-check authorization, and their destructive actions carry no ->authorize(). Because each Livewire component handles its own /livewire/update requests, the action executes purely on the page-level access_setting gate — there is no per-resource permission, and delete_zones / delete_taxes permissions are never even generated by the seeder (packages/admin/database/seeders/PermissionsTableSeeder.php).

ZoneShippingOptions::deleteAction() is the clearest case — it deletes by an id taken straight from the client action arguments with no scoping and no permission check:

// packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php
public function deleteAction(): Action
{
    return Action::make('delete')
        ->requiresConfirmation()
        // ... no ->authorize(), no ->visible()
        ->action(function (array $arguments): void {
            CarrierOption::query()->find($arguments['id'])->delete();   // client-controlled id
            // ...
        });
}

Proof of Concept

Confirmed with the project's own test harness (Pest + Orchestra Testbench, SQLite) — the real Livewire/Filament code path, executed as a non-admin user holding only access_setting.

use Livewire\Livewire;
use Shopper\Core\Models\{CarrierOption, Zone};
use Shopper\Livewire\Components\Settings\Zones\ZoneShippingOptions;
use Tests\Core\Stubs\User;

uses(Tests\Admin\TestCase::class);

it('low-priv access_setting user deletes a CarrierOption with no authorization', function (): void {
    $attacker = User::factory()->create();
    $attacker->givePermissionTo('access_setting');          // NOT admin, NO delete_* permission
    $this->actingAs($attacker, config('shopper.auth.guard'));

    $zone   = Zone::factory()->create();
    $option = CarrierOption::factory()->create(['zone_id' => $zone->id]);

    Livewire::test(ZoneShippingOptions::class, ['selectedZoneId' => $zone->id])
        ->callAction('delete',…
Record
GHSA-f7h9-qv4x-9x57
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-862
Updated
2026-11-02
NVD 5.4

Shopper is a Headless e-commerce Admin Panel. From 2.0.0 until 2.9.2, authenticated users who could reach the Settings pages with only access_setting could directly invoke destructive actions through the Livewire endpoint because packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php, packages/admin/src/Livewire/Components/Settings/Zones/Detail.php, packages/admin/src/Livewire/Components/Settings/Taxes/Detail.php, and packages/admin/src/Livewire/Components/Settings/Taxes/TaxRates.php did not enforce server-side delete authorization. The actions could delete carrier options, shipping zones, tax zones, and tax rates, disrupting checkout shipping, payment-method mapping, and tax calculation. This issue is fixed in version 2.9.2.

Record
CVE-2026-56826
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-862
Updated
2026-11-02
OSV 5.4

Shopper: Missing function-level authorization on Settings tax/zone/shipping Livewire components allows a low-privileged user to delete commerce configuration

Shopper is a Headless e-commerce Admin Panel. From 2.0.0 until 2.9.2, authenticated users who could reach the Settings pages with only access_setting could directly invoke destructive actions through the Livewire endpoint because packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php, packages/admin/src/Livewire/Components/Settings/Zones/Detail.php, packages/admin/src/Livewire/Components/Settings/Taxes/Detail.php, and packages/admin/src/Livewire/Components/Settings/Taxes/TaxRates.php did not enforce server-side delete authorization. The actions could delete carrier options, shipping zones, tax zones, and tax rates, disrupting checkout shipping, payment-method mapping, and tax calculation. This issue is fixed in version 2.9.2.

Record
CVE-2026-56826
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-862
Updated
2026-11-02
OSVGHSA-f7h9-qv4x-9x57 5.4

Shopping privilege escalation through missing authorization in Settings components

Summary

Four Livewire components in the Settings area expose destructive Filament actions (delete / edit) that perform no server-side authorization. Any authenticated user who can reach the Settings pages — i.e. holding only the coarse access_setting permission, without being an admin and without any delete_*/edit_* permission — can delete tax zones, tax rates, shipping zones, and carrier (shipping-rate) options by invoking the component action directly over the Livewire endpoint.

These records sit on the storefront checkout path, so deleting them breaks shipping-rate calculation, removes region-scoped payment methods, and corrupts tax resolution at checkout.

This is inconsistent with the rest of the admin, where destructive actions are gated by granular permissions (e.g. Settings/Locations/Index uses ->authorize('delete_inventories'), and Order/Detail gates mutating actions with edit_orders).

Affected components

| Component | File | Unauthorized action | |---|---|---| | Settings\Zones\ZoneShippingOptions | packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php:47 | delete → CarrierOption::query()->find($arguments['id'])->delete() (id is client-supplied) | | Settings\Zones\Detail | packages/admin/src/Livewire/Components/Settings/Zones/Detail.php:46 | delete → DeleteAction on the bound Zone | | Settings\Taxes\Detail | packages/admin/src/Livewire/Components/Settings/Taxes/Detail.php:42 | delete → DeleteAction on the bound TaxZone | | Settings\Taxes\TaxRates | packages/admin/src/Livewire/Components/Settings/Taxes/TaxRates.php:97 | delete → DeleteAction on a TaxRate |

Each file contains zero authorize calls, and the actions declare neither ->authorize() nor an enforced ->visible() guard.

Details

The Settings pages mount these as child Livewire components. The parent page authorizes access_setting (e.g. Pages/Settings/Taxes.php:29), but the child components do not re-check authorization, and their destructive actions carry no ->authorize(). Because each Livewire component handles its own /livewire/update requests, the action executes purely on the page-level access_setting gate — there is no per-resource permission, and delete_zones / delete_taxes permissions are never even generated by the seeder (packages/admin/database/seeders/PermissionsTableSeeder.php).

ZoneShippingOptions::deleteAction() is the clearest case — it deletes by an id taken straight from the client action arguments with no scoping and no permission check:

// packages/admin/src/Livewire/Components/Settings/Zones/ZoneShippingOptions.php
public function deleteAction(): Action
{
    return Action::make('delete')
        ->requiresConfirmation()
        // ... no ->authorize(), no ->visible()
        ->action(function (array $arguments): void {
            CarrierOption::query()->find($arguments['id'])->delete();   // client-controlled id
            // ...
        });
}

Proof of Concept

Confirmed with the project's own test harness (Pest + Orchestra Testbench, SQLite) — the real Livewire/Filament code path, executed as a non-admin user holding only access_setting.

use Livewire\Livewire;
use Shopper\Core\Models\{CarrierOption, Zone};
use Shopper\Livewire\Components\Settings\Zones\ZoneShippingOptions;
use Tests\Core\Stubs\User;

uses(Tests\Admin\TestCase::class);

it('low-priv access_setting user deletes a CarrierOption with no authorization', function (): void {
    $attacker = User::factory()->create();
    $attacker->givePermissionTo('access_setting');          // NOT admin, NO delete_* permission
    $this->actingAs($attacker, config('shopper.auth.guard'));

    $zone   = Zone::factory()->create();
    $option = CarrierOption::factory()->create(['zone_id' => $zone->id]);

    Livewire::test(ZoneShippingOptions::class, ['selectedZoneId' => $zone->id])
        ->callAction('delete',…
Record
GHSA-f7h9-qv4x-9x57
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-862
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
shopper/framework
Packagist
2.0.0 up to 2.9.2
2.9.2
shopper/framework
Packagist
2.0.0 up to 2.9.2, plus listed versions
v2.0.0v2.0.1v2.0.2v2.0.3v2.1.1
Show 36 moreShow less
v2.1.2v2.1.3v2.1.4v2.1.5v2.1.6v2.2v2.2.1v2.2.2v2.2.3v2.2.4v2.2.5v2.2.6v2.2.7v2.3v2.3.1v2.3.2v2.3.3v2.4.0v2.4.1v2.4.2v2.4.3v2.5.0v2.5.1v2.6.0v2.6.1v2.6.2v2.6.3v2.6.4v2.7.0v2.7.1v2.7.2v2.7.3v2.8.0v2.8.1v2.9.0v2.9.1
2.9.2

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-56826 is a medium vulnerability (CVSS 5.4) in Shopperdotcom Shopper, published September 11, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 27th percentile. Fixed in shopper/framework 2.9.2.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open