CVE-2026-31824: 
PHP vulnerability analysis and mitigation

Overview

CVE-2026-31824 is a Time-of-Check To Time-of-Use (TOCTOU) race condition vulnerability in Sylius, an open-source eCommerce framework built on Symfony, that allows unauthenticated attackers to bypass promotion and coupon usage limits. The vulnerability was published on March 9, 2026, and affects all major Sylius branches: ≤1.9.11, 1.10.0–1.10.15, 1.11.0–1.11.16, 1.12.0–1.12.22, 1.13.0–1.13.14, 1.14.0–1.14.17, 2.0.0–2.0.15, 2.1.0–2.1.11, and 2.2.0–2.2.2. The GitHub Advisory Database assigns a CVSS v3.1 score of 8.2 (High) (GitHub Advisory), while NVD records a base score of 5.9 (Medium) (Feedly). The vulnerability was responsibly disclosed by Djibril Mounkoro (@whiteov3rflow) and Bartłomiej Nowiński (@bnBart) (Sylius Advisory).

Technical details

The root cause is a TOCTOU race condition (CWE-362, CWE-367) in the OrderPromotionsUsageModifier service, which governs three independent usage limits: the global promotion usage counter, the global coupon usage counter, and the per-customer coupon redemption count. During order validation, eligibility checks read the used counter from an in-memory Doctrine entity; however, the actual increment occurs later during order completion with no database-level locking or atomic operations between the two phases. Critically, Doctrine flushes an absolute value (SET used = 1) rather than an atomic increment (SET used = used + 1), and the affected entities lack optimistic locking — meaning concurrent requests all read the same stale counter and simultaneously pass eligibility checks. The vulnerable endpoint is PATCH /api/v2/shop/orders/{token}/complete, which can be called without authentication (Sylius Advisory, GitHub Advisory).

Impact

Successful exploitation allows an attacker to redeem a single-use promotion or coupon an arbitrary number of times, resulting in direct financial loss for the merchant. All three limit types — global promotion usage, global coupon usage, and per-customer coupon usage — are bypassed simultaneously, meaning no enforcement mechanism remains effective under concurrent load. There is no confidentiality impact, but integrity is severely affected as order and discount data becomes inconsistent; availability may also be marginally impacted. No authentication is required, making this exploitable by any external actor with network access to the Sylius API (Sylius Advisory).

Exploitability

No public proof-of-concept exploit code has been identified, and there is no evidence of active in-the-wild exploitation at this time (Feedly). The EPSS score is approximately 0.067% (21st percentile), indicating a low near-term exploitation probability (GitHub Advisory). The vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. No threat actor attribution has been reported. Despite the low EPSS, the attack requires no authentication and only moderate timing coordination, making it accessible to motivated attackers targeting eCommerce platforms.

Exploitation steps

  1. Reconnaissance: Identify a Sylius-powered eCommerce site running a vulnerable version (≤1.9.11, 1.10.0–1.10.15, 1.11.0–1.11.16, 1.12.0–1.12.22, 1.13.0–1.13.14, 1.14.0–1.14.17, 2.0.0–2.0.15, 2.1.0–2.1.11, or 2.2.0–2.2.2) by checking publicly exposed version indicators or API responses.
  2. Identify a limited-use promotion or coupon: Browse the storefront or probe the API to find a promotion or coupon with a usage limit (e.g., a single-use discount code).
  3. Prepare multiple carts: Create multiple shopping carts (sessions or accounts) and apply the same limited-use promotion or coupon code to each cart, bringing each to the ready-to-complete state.
  4. Fire simultaneous completion requests: Using a tool such as curl with parallel execution, Python's asyncio/aiohttp, or a load-testing tool like ab or wrk, send concurrent PATCH /api/v2/shop/orders/{token}/complete requests for all prepared carts at the same time.
  5. Exploit the race window: Because all concurrent requests read the same stale in-memory used counter (e.g., used = 0) before any increment is flushed, all pass the eligibility check and complete successfully — each order receiving the discount.
  6. Collect results: All orders are completed with the promotion applied, effectively redeeming the coupon an unlimited number of times and obtaining unauthorized discounts (Sylius Advisory, GitHub Advisory).

Indicators of compromise

  • Network: Burst of simultaneous or near-simultaneous PATCH /api/v2/shop/orders/{token}/complete requests from the same IP or user account within a very short time window (milliseconds to low seconds).
  • Logs: Web server or API access logs showing multiple order completion requests for different order tokens in rapid succession, all returning HTTP 200 success responses; repeated use of the same promotion or coupon code across multiple completed orders in application logs.
  • Database: The used column in sylius_promotion or sylius_promotion_coupon tables showing a value lower than the actual number of completed orders referencing that promotion/coupon; multiple sylius_order records in non-cart state all referencing the same promotion_coupon_id with a count exceeding the configured usage_limit or per_customer_usage_limit.
  • Application Behavior: Promotion or coupon used counter not incrementing correctly relative to the number of completed orders; orders completing successfully after a promotion should have been exhausted.

Mitigation and workarounds

Sylius has released patched versions addressing this vulnerability: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, and 2.2.3. Upgrading to the appropriate patched version is the recommended remediation. For sites that cannot upgrade immediately, a workaround is available: decorate the OrderPromotionsUsageModifier service (service ID sylius.modifier.promotion.order_usage for Sylius ≥2.0, or sylius.promotion_usage_modifier for <2.0) with a custom implementation that uses atomic SQL operations (SET used = used + 1) and database-level row locking (FOR UPDATE) instead of in-memory Doctrine entity reads. After applying the decorator, optionally map Doctrine\ORM\OptimisticLockException to HTTP 409 in API Platform configuration, then clear the cache with bin/console cache:clear (Sylius Advisory, GitHub Advisory).

Community reactions

Sylius published an official security blog post covering this and related vulnerabilities for both 1.x and 2.x version branches (Sylius Blog). The advisory credits researchers Djibril Mounkoro (@whiteov3rflow) and Bartłomiej Nowiński (@bnBart) for responsible disclosure (Sylius Advisory). No significant broader media coverage or notable social media discussion has been identified beyond standard CVE aggregator publications.

Additional resources

  • Sylius Advisory — Official Sylius security advisory with full technical details and workaround code
  • GitHub Advisory — GitHub Advisory Database entry (GHSA-7mp4-25j8-hp5q)
  • Sylius Blog — Sylius official security blog post for 1.x and 2.x versions

Source: This report was generated using AI

Related PHP vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

CVE-2026-55224HIGH8.7
  • PHP logoPHP
  • mineadmin/mineadmin
NoYesSep 30, 2026
CVE-2026-103111HIGH7.6
  • MariaDB Server logoMariaDB Server
  • mariadb11.8-server
NoYesSep 30, 2026
GHSA-3q6v-r5mr-hxv8HIGH7.5
  • PHP logoPHP
  • league/commonmark
NoYesSep 30, 2026
GHSA-97jj-33gv-5xf9MEDIUM6.1
  • PHP logoPHP
  • league/commonmark
NoYesSep 30, 2026
CVE-2026-104181MEDIUM5.4
  • PHP logoPHP
  • filament/filament
NoYesOct 01, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management