PT-2026-44439 · Packagist · Shopper/Cart
Published
2026-05-18
·
Updated
2026-05-18
CVSS v3.1
5.9
Medium
| Vector | AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N |
Impact
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.A second related bug:
usage limit per user was effectively a no-op because the counter it relied on (DiscountDetail.total use) was never incremented anywhere in the codebase. The per-user check therefore always saw 0 uses and validation passed regardless of how many times the same customer had previously redeemed the coupon. For eligibility = Everyone the per-user limit could not fire at all because the underlying DiscountDetail row only exists for eligibility = Customers.Direct financial loss: each over-redemption is a discount the merchant did not intend to grant.
Patches
Fixed in
v2.8.0. CreateOrderFromCartAction now:- Reserves the discount slot atomically before the order row is created, inside the same
DB::transactionwithlockForUpdateand a compare-and-swap ontotal use. - Throws
DiscountLimitReachedException::globaland rolls back the transaction when the global limit was exhausted between cart validation and commit. No order is committed. - Throws
DiscountLimitReachedException::perUserand rolls back when the discount is restricted to one use per customer and the customer has already redeemed it. - Snapshots
discount id,discount code,discount type,discount value at applyanddiscount currency codeonto theorderstable for resilience against later discount edits or deletions.
DiscountValidator was updated to perform the same Order-based per-user check at cart-apply time so the rejection is surfaced before checkout.Upgrade via:
composer require shopper/cart:^2.8 shopper/core:^2.8
php artisan migrateWorkarounds
None. Upgrade to
v2.8.0.Resources
- Issue: https://github.com/shopperlabs/shopper/issues/510
- Pull request: https://github.com/shopperlabs/shopper/pull/511
- CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization
Fix
Race Condition
Found an issue in the description? Have something to add? Feel free to write us 👾
Weakness Enumeration
Related Identifiers
Affected Products
Shopper/Cart