Skip to main content

Shopper EUVDEUVD-2026-33409

| CVE-2026-47741 MEDIUM
Race Condition (CWE-362)
2026-05-29 GitHub_M
5.9
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
5.9 MEDIUM
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N
Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
High
Availability
None

Lifecycle Timeline

3
Patch available
May 29, 2026 - 20:02 EUVD
Source Code Evidence Fetched
May 29, 2026 - 19:00 vuln.today
Analysis Generated
May 29, 2026 - 19:00 vuln.today

DescriptionGitHub Advisory

Shopper is a Headless e-commerce Admin Panel. Prior to 2.8.0, CreateOrderFromCartAction::execute previously created the Order row before checking and incrementing the discount's total_use counter. Under concurrent checkout pressure (Black Friday, flash sale, viral coupon), the global usage_limit was silently exceeded: orders were committed with the discount fully applied to price_amount while the counter blocked at usage_limit. The merchant had no signal that an over-redemption had occurred. This vulnerability is fixed in 2.8.0.

AnalysisAI

Discount over-redemption via race condition in Shopper (shopperlabs/shopper prior to v2.8.0) allows concurrent unauthenticated checkout requests to bypass a coupon's global usage_limit, resulting in committed orders carrying unauthorized discounts the merchant never intended to grant. The CreateOrderFromCartAction::execute method created the Order database row before atomically reserving the discount slot, opening a classic TOCTOU window that becomes reliably exploitable under the high-concurrency traffic of flash sales or Black Friday events. A compounding bug rendered usage_limit_per_user entirely non-functional in all pre-2.8.0 versions - the underlying counter was never incremented anywhere in the codebase - meaning per-user caps provided zero protection regardless of a customer's redemption history. No public exploit identified at time of analysis; this CVE is not listed in CISA KEV.

Technical ContextAI

The vulnerability exists in the shopperlabs/shopper PHP Composer packages (shopper/cart and shopper/core), a Laravel-based headless e-commerce admin panel (CPE: cpe:2.3:a:shopperlabs:shopper:*:*:*:*:*:*:*:*). The root cause maps precisely to CWE-362 (Concurrent Execution using Shared Resource with Improper Synchronization). The CreateOrderFromCartAction::execute method performed a non-atomic check-then-act sequence: it read the discount's total_use value, validated it against usage_limit, committed the Order row to the database, and only then incremented total_use - without holding a database lock across these operations. This creates a TOCTOU window where multiple concurrent HTTP requests can simultaneously read the same pre-limit total_use value, all pass validation independently, and all commit orders with the discount applied before any counter increment is written. The fix in v2.8.0 wraps the entire sequence inside a DB::transaction using lockForUpdate with a compare-and-swap on total_use, making the reservation atomic and rolling back with DiscountLimitReachedException if the limit was exhausted between cart validation and commit. The secondary defect - DiscountDetail.total_use never being incremented - meant the per-user check perpetually observed 0 prior uses; for eligibility=Everyone discounts, the requisite DiscountDetail row did not even exist, making the per-user path entirely unreachable.

RemediationAI

Upgrade both shopper/cart and shopper/core to version 2.8.0 by running 'composer require shopper/cart:^2.8 shopper/core:^2.8' followed by 'php artisan migrate' - the migration step is required to apply schema changes that snapshot discount metadata (discount_id, discount_code, discount_type, discount_value_at_apply, discount_currency_code) onto the orders table for audit resilience. The fix is confirmed in PR #511 (commit fcd0c5920588702df5b874f432b1042abd77a50b) and detailed in the vendor advisory at https://github.com/shopperlabs/shopper/security/advisories/GHSA-9rh9-hf3w-9fgg. The vendor explicitly states no workarounds exist. As an emergency compensating control prior to upgrading, operators can disable all discount codes with usage limits entirely, eliminating the financial exposure at the cost of all promotional functionality. Setting artificially low usage_limit values does not prevent the race condition but limits the magnitude of over-redemption per campaign. Neither compensating control addresses the per-user limit bug, which requires the v2.8.0 code fix.

Share

EUVD-2026-33409 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy