Sep 15, 2026·6 min read·17 visits
Missing server-side authorization in Shopper's Livewire Media component allows low-privilege staff to maliciously overwrite product images.
An incomplete security fix in Shopper prior to version 2.9.2 exposes a Broken Function Level Authorization (BFLA) vulnerability in the Media component. Low-privileged administrative users with 'browse_products' permissions can bypass role-based access control policies to execute the 'store' action and modify product media.
Shopper is a headless e-commerce admin panel built on Laravel. The administrative interface relies heavily on Laravel Livewire to handle dynamic component-state updates via client-side AJAX requests. In versions prior to 2.9.2, Shopper suffers from a Broken Function Level Authorization (BFLA) vulnerability designated as CVE-2026-56830. This flaw allows low-privilege users possessing the browse_products permission to execute restricted write actions.
The attack surface is exposed via the standard Livewire update endpoint located at /livewire/update. Under normal operations, Livewire components serialize and transmit state snapshots to the client, which subsequently returns them when initiating actions. Due to a missing authorization check in the Media sub-form component, an authenticated low-privilege staff member can bypass intended privilege boundaries and perform unauthorized state modifications.
The target of this vulnerability is the Media.php component, which is responsible for managing product image assets and galleries. Exploitation of this vulnerability does not lead to remote code execution directly, but it enables unauthorized modification of crucial e-commerce database records and media associations. This undermines system integrity and allows malicious product defacement.
The root cause of CVE-2026-56830 lies in a missing server-side authorization check inside the store() method of the Media Livewire component. During a prior security patch (remediating GHSA-h4mp-g9c6-xwph), Shopper developers intended to secure administrative actions by locking state variables and validating permissions. While sibling components received explicit authorization directives, the Media component was omitted from these protections.
Laravel Livewire exposes all public component methods to client-side invocation. Because the client can request the execution of any public method by targeting /livewire/update, developers must enforce strict access control checks directly within those methods. The Media sub-form component (packages/admin/src/Livewire/Components/Products/Form/Media.php) implements a public store() method that performs database updates, but lacks any permission verification.
While the underlying $product property is protected by the #[Locked] attribute (which prevents attackers from changing the targeted product ID on the client side), the absence of a permission check allows any authenticated session with minimum rights to invoke store(). An attacker who can view a product can capture the Livewire snapshot of that product's media component and trigger the update action, bypassing the application's RBAC model.
Before the patch, the store() method in packages/admin/src/Livewire/Components/Products/Form/Media.php was vulnerable. The code validated input and immediately updated the product model using form state without checking user privileges.
// Vulnerable Code Path
public function store(): void
{
// No authorization check is performed here
$this->validate();
$this->product->update($this->form->getState());
$this->dispatch('product.updated');
Notification::make()
->body(__('shopper::pages/products.notifications.media_update'))
->success()
->send();
}To resolve this vulnerability, the fix in commit bf72e2753e21296184596d507336c7d65ecd46ff introduces an explicit call to the authorize method. This forces Laravel's underlying authorization system to evaluate whether the authenticated user holds the required edit_products permission.
// Patched Code Path
public function store(): void
{
// Enforce authorization prior to validation or model mutation
$this->authorize('edit_products');
$this->validate();
$this->product->update($this->form->getState());
$this->dispatch('product.updated');
Notification::make()
->body(__('shopper::pages/products.notifications.media_update'))
->success()
->send();
}The fix is robust for this specific component because it prevents execution of any database write operations prior to verifying security policies. Additionally, the patch implemented similar authorization checks across multiple sibling controllers and actions, closing other outstanding administrative security gaps.
Exploiting CVE-2026-56830 requires an active session with low-level administrative privileges (specifically browse_products). The attacker must navigate to a product detail or browse page to retrieve the target product's Livewire snapshot. This snapshot contains the serialized component state required to perform transactions on /livewire/update.
Once the snapshot is acquired, the attacker crafts a POST request to /livewire/update. The payload must specify the shopper.products.form.media component name and include the extracted snapshot. In the updates object, the attacker defines the malicious parameters (such as form.thumbnail or form.gallery), and in the calls array, they request the execution of the store method.
An automated Python script can facilitate this attack by extracting the necessary CSRF token and session cookies, formatting the nested JSON parameters, and transmitting the payload to the server. If successful, the server responds with a status code of 200 and performs the unauthorized media update, which can be verified by observing the defaced product page.
The security impact of CVE-2026-56830 is classified as high for system integrity, resulting in a CVSS v3.1 base score of 6.5 (Medium). The vulnerability allows low-privileged staff members to compromise the integrity of the store's product catalog. An attacker can replace authentic product images with fraudulent, malicious, or offensive imagery, severely damaging the brand's reputation.
Because the scope is restricted to the Shopper application itself, the vulnerability has a CVSS scope metric of Unchanged. It does not allow for cross-site scripting (XSS), local file inclusion (LFI), or remote code execution (RCE) directly. The confidentiality and availability metrics are rated as None, as the vulnerability does not leak database credentials or cause service downtime.
This flaw represents a significant risk in multi-tenant or multi-tier administrative setups where staff permissions are strictly segregated. Trust assumptions between low-privilege product catalog browsers and high-privilege store managers are violated. It is critical to address this vulnerability to maintain administrative boundary isolation.
The primary mitigation for CVE-2026-56830 is upgrading the Shopper installation to version 2.9.2 or later. This release incorporates the authorization fixes in the core admin package and secures the Livewire endpoints against unauthorized calls. Running composer update shopperlabs/shopper in the application root will fetch the patched dependency.
In environments where immediate upgrading is not possible, a manual hotfix must be applied to the vendor files. Developers can locate the Media.php controller file within the Shopper package and manually add $this->authorize('edit_products'); as the first line of the store() method. This ensures that the application checks the user's role before processing validation or updates.
Furthermore, organization security teams should implement defensive monitoring on web application firewalls (WAFs). Logging and analyzing traffic to /livewire/update for request payloads invoking store on the shopper.products.form.media component can assist in detecting exploitation attempts. Conducting routine permission audits across all administrative accounts is also highly recommended.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
shopperlabs/shopper shopperlabs | < 2.9.2 | 2.9.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 6.5 |
| Impact | High Integrity Loss (I:H) |
| Exploit Status | Proof of Concept (PoC) Available |
| CISA KEV Status | Not Listed |
The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
A credential exposure vulnerability exists in the @sigstore/oci library prior to version 0.7.2. The RegistryClient implementation stores sensitive authentication headers, including Bearer tokens, Basic authentication credentials, and custom Docker configuration headers, as client-wide defaults on its shared HTTP client instance. When uploading binary blobs via the OCI distribution specification, the client extracts the target upload URI from the server-supplied Location header and dispatches an independent HTTP PUT request. If a compromised or untrusted registry returns a cross-origin URI in the Location header, the client transmits the stored authentication credentials directly to the third-party host.
An OS command injection and argument injection vulnerability exists in the Nx build system and its official Maven (@nx/maven) and Gradle (@nx/gradle) plugins. When constructing the project dependency graph, the plugins invoke underlying Java build wrappers via subshells while interpolating unsanitized plugin options directly from nx.json into the command arguments. An attacker who supplies a crafted nx.json file via a repository or pull request can execute arbitrary shell commands with the privileges of the user or CI/CD runner invoking any Nx command that computes the project graph.
AdminNeo versions 4.6.2 through 5.4.1 contain an improper input validation vulnerability (CWE-20) in the version verification endpoint (?script=version). An unauthenticated remote attacker can submit a crafted HTTP POST request containing an array parameter for 'version', which is serialized into a shared server-side temporary cache file without type checking or authentication. On subsequent requests, the application deserializes this cached array and passes it to cookie() and rawurlencode(), triggering an uncaught fatal TypeError in PHP 8.x environments and causing a persistent 24-hour Denial of Service (DoS) for all users.
Charmbracelet Soft Serve versions 0.5.0 through 0.12.2 contain an authorization bypass and observable response discrepancy vulnerability in the HTTP Git server. Remote attackers can determine the existence, exact names, and clone URLs of private repositories by issuing crafted Go remote import path discovery requests (?go-get=1) or by observing differential HTTP status codes across Git Smart HTTP, Dumb HTTP, and Git LFS endpoints.
A Time-of-Check to Time-of-Use (TOCTOU) race condition in Charmbracelet Soft Serve versions 0.6.0 through 0.12.2 allows unauthenticated users to retain read access to repositories after their visibility is changed from public to private. The flaw stems from premature cache invalidation in the SetPrivate method prior to committing the visibility update to the underlying database. Concurrent read requests arriving during the database transaction window repopulate the non-expiring in-memory LRU cache with stale public metadata, bypassing access controls across HTTP, SSH, and Git protocols until the server process is restarted.
A resource consumption vulnerability exists in the Authlib joserfc Python library prior to version 1.7.5. When processing JSON Web Encryption (JWE) objects formatted using General JSON Serialization, the library fails to enforce an upper bound on the number of elements within the recipients array. An unauthenticated attacker can supply a JWE containing thousands of recipient entries targeting an RSA key management algorithm, forcing the server to perform an equivalent number of computationally expensive RSA private-key decryption operations per request and exhausting available CPU resources.