Sylius CVE-2026-53637
MEDIUMSeverity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
Attacker controls the race condition timing themselves (AC:L); authenticated customer session required (PR:L); order deletion is integrity impact only, no confidentiality or availability component.
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
Lifecycle Timeline
1DescriptionGitHub Advisory
Impact
A user opens the cart page in the browser. In the background, the order gets completed, e.g. an admin changes the status, or the user finalizes payment in another tab. The browser still displays the old cart: the LiveComponent is unaware the underlying order state has changed.
If the user then:
- clears the cart →
clearCart()callsmanager->remove()on the
completed order: the order is permanently deleted from the database;
- removes a product →
removeItem()mutates an item on the completed
order;
- changes quantity →
saveCart()overwrites data on the completed order.
In all cases, the customer's order data is irreversibly corrupted or lost, even though the order has already been placed and paid for. The same vector can be triggered deliberately by an authenticated customer (keep the cart page open, complete checkout in another tab, then modify the "cart" to add quantity beyond what was paid for).
Patches
The issue is fixed in versions: 2.0.18, 2.1.15, 2.2.6 and above.
Workarounds
If users cannot update Sylius immediately, they should create a patched copy of the affected class in their application's src/ directory and override the Sylius service definition to use it.
Step 1. Create src/Twig/Component/Cart/FormComponent.php
<?php
declare(strict_types=1);
namespace App\Twig\Component\Cart;
use Doctrine\Persistence\ObjectManager;
use Sylius\Bundle\UiBundle\Twig\Component\ResourceFormComponentTrait;
use Sylius\Bundle\UiBundle\Twig\Component\TemplatePropTrait;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\OrderCheckoutStates;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Sylius\Component\Order\SyliusCartEvents;
use Sylius\Resource\Model\ResourceInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveArg;
use Symfony\UX\LiveComponent\Attribute\PreReRender;
use Symfony\UX\LiveComponent\ComponentToolsTrait;
class FormComponent
{
use ComponentToolsTrait;
/** @use ResourceFormComponentTrait<OrderInterface> */
use ResourceFormComponentTrait;
use TemplatePropTrait;
public const SYLIUS_SHOP_CART_CHANGED = 'sylius:shop:cart_changed';
public const SYLIUS_SHOP_CART_CLEARED = 'sylius:shop:cart_cleared';
public bool $shouldSaveCart = true;
/** @param OrderRepositoryInterface<OrderInterface> $orderRepository */
public function __construct(
OrderRepositoryInterface $orderRepository,
FormFactoryInterface $formFactory,
string $resourceClass,
string $formClass,
protected readonly ObjectManager $manager,
protected readonly EventDispatcherInterface $eventDispatcher,
) {
$this->initialize($orderRepository, $formFactory, $resourceClass, $formClass);
}
public function hydrateResource(mixed $value): ?ResourceInterface
{
if (empty($value)) {
return $this->createResource();
}
/** @var OrderInterface|null $order */
$order = $this->repository->find($value);
if (
!$order instanceof OrderInterface
|| $order->getCheckoutState() === OrderCheckoutStates::STATE_COMPLETED
) {
return $this->createResource();
}
return $order;
}
#[PreReRender(priority: -100)]
public function saveCart(): void
{
if ($this->shouldSaveCart && $this->resource?->getId() !== null) {
$form = $this->getForm();
if ($form->isValid()) {
$this->eventDispatcher->dispatch(new GenericEvent($form->getData()), SyliusCartEvents::CART_CHANGE);
$this->manager->flush();
$this->emit(self::SYLIUS_SHOP_CART_CHANGED, ['cartId' => $this->resource->getId()]);
}
}
}
#[LiveAction]
public function removeItem(#[LiveArg] int $index): void
{
if ($this->resource?->getId() === null) {
return;
}
$data = $this->formValues['items'];
unset($data[$index]);
$this->formValues['items'] = array_values($data);
$orderItem = $this->resource->getItems()->get($index);
$this->eventDispatcher->dispatch(new GenericEvent($orderItem), SyliusCartEvents::CART_ITEM_REMOVE);
$this->manager->persist($this->resource);
$this->manager->flush();
$this->manager->refresh($this->resource);
$this->shouldSaveCart = false;
$this->submitForm();
$this->emit(self::SYLIUS_SHOP_CART_CHANGED, ['cartId' => $this->resource->getId()]);
}
#[LiveAction]
public function clearCart(): void
{
if ($this->resource?->getId() === null) {
return;
}
$this->formValues['items'] = [];
$this->eventDispatcher->dispatch(new GenericEvent($this->resource), SyliusCartEvents::CART_CLEAR);
$this->manager->remove($this->resource);
$this->manager->flush();
$this->resource = $this->createResource();
$this->resetForm();
$this->isValidated = false;
$this->validatedFields = [];
$this->shouldSaveCart = false;
$this->submitForm();
$this->emit(self::SYLIUS_SHOP_CART_CLEARED);
}
#[LiveAction]
public function removeCoupon(): void
{
$this->formValues['promotionCoupon'] = '';
$this->submitForm();
}
private function getDataModelValue(): string
{
return 'debounce(500)|*';
}
}Step 2. Override the Sylius service in config/services.yaml
Append to the application's config/services.yaml (or a dedicated file loaded by the kernel, e.g. config/packages/sylius_security_cart.yaml):
services:
sylius_shop.twig.component.cart.form:
class: App\Twig\Component\Cart\FormComponent
arguments:
- '@sylius.repository.order'
- '@form.factory'
- '%sylius.model.order.class%'
- 'Sylius\Bundle\ShopBundle\Form\Type\CartType'
- '@doctrine.orm.entity_manager'
- '@event_dispatcher'
calls:
- [setLiveResponder, ['@ux.live_component.live_responder']]
tags:
- { name: sylius.live_component.shop, key: 'sylius_shop:cart:form' }This redeclares the existing Sylius service id sylius_shop.twig.component.cart.form so it instantiates the patched class from App\ while preserving every argument, call and tag from the original Sylius XML definition. The cart twig hook keeps resolving to the same Live Component key (sylius_shop:cart:form).
Step 3. Clear the cache
bin/console cache:clearReporters
We would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability:
- Kévin Gonella (@kgonella)
- Sam V.
For more information
If there are any questions or comments about this advisory:
- Open an issue in Sylius issues
- Send an email to [security@sylius.com](mailto:security@sylius.com)
AnalysisAI
Order data corruption and permanent deletion in Sylius affects authenticated customers across versions prior to 2.0.18, 2.1.15, and 2.2.6 due to a stale-state race condition in the cart LiveComponent. When an order transitions to STATE_COMPLETED while a customer's cart page remains open in a browser tab, subsequent cart actions - clearing, removing items, or adjusting quantities - are applied to the completed order rather than a fresh cart, irreversibly deleting or mutating finalized order records. …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | Exploitation requires an authenticated customer session (CVSS PR:L confirmed). … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | The vendor-assigned CVSS 6.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N) accurately reflects the core risk profile: network-accessible exploitation by any authenticated customer account with high integrity impact and no privilege escalation across scope boundaries. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | An authenticated customer opens the cart page in Tab A, then completes checkout and payment in Tab B. Tab A continues to display the old cart LiveComponent, which still holds a reference to the now-completed order entity. … |
| Remediation | Upgrade to Sylius 2.0.18, 2.1.15, or 2.2.6 (or any later release within the respective branch), which introduce a completed-state guard in `hydrateResource()` that prevents cart mutations from operating on finalized orders. … Detailed patch versions, workarounds, and compensating controls in full report. |
Threat intelligence, references, and detailed analysis are available after sign-in.
sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not
(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear
ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C
Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au
Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c
Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows
The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1
NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro
The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all
Same technique Information Disclosure
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-5597-7rmh-97q5