CVE-2026-53639: Sylius Payment Request API IDOR Vulnerability
Summary
CVE-2026-53639: Sylius: IDOR on Shop Payment Request API endpoints. Affects sylius/sylius across 3 version ranges.
>= 2.0.0, < 2.0.18
>= 2.1.0, < 2.1.15
>= 2.2.0, < 2.2.6
Fixed in 2.0.18, 2.1.15 or 2.2.6, depending on the release line you run. How to fix ↓
Check if this vulnerability affects your application
Upload a manifest or SBOM and we'll show whether you're affected, plus every other risky package in the same scan.
No signup required · Results in about 60 seconds
Background
Sylius is an open-source eCommerce platform built on Symfony, designed to provide a robust and flexible framework for online stores. It offers features such as product management, order processing, and payment handling. However, it has been identified that certain API endpoints related to payment requests are vulnerable to Insecure Direct Object Reference (IDOR), allowing unauthorized access to sensitive information.
Vulnerability Detail
The vulnerability exists in the 'GET /api/v2/shop/payment-requests/{hash}' and 'PUT /api/v2/shop/payment-requests/{hash}' endpoints, which retrieve payment requests based solely on the hash provided in the URL. There is no ownership verification for the authenticated customer or the associated order. An attacker can exploit this by obtaining a payment request hash, allowing them to read sensitive order details and modify the payment request payload, potentially redirecting users to malicious URLs. This vulnerability arises from inadequate access control measures.
How To Fix
Fixed versions by release line
The minimum fixed version depends on the release line you run.
-
>= 2.0.0, < 2.0.182.0.18composer require sylius/sylius:2.0.18 -
>= 2.1.0, < 2.1.152.1.15composer require sylius/sylius:2.1.15 -
>= 2.2.0, < 2.2.62.2.6composer require sylius/sylius:2.2.6
Tip — Not sure which release line you're on? Vulert can find the fix for the version you are using. Scan free →
Workaround
Until you can upgrade, implement the following workaround to enforce ownership checks on the existing endpoints. Create a query extension to filter the 'GET' operation and a state provider for the 'PUT' operation. Below is an example of the code for the query extension:
<?php
declare(strict_types=1);
namespace App\ApiPlatform\QueryExtension;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\QueryBuilder;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiSection;
use Sylius\Bundle\CoreBundle\SectionResolver\SectionProviderInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
use Sylius\Component\Payment\Model\PaymentRequestInterface;
final readonly class PaymentRequestOwnershipExtension implements QueryItemExtensionInterface
{
public function __construct(
private SectionProviderInterface $sectionProvider,
private UserContextInterface $userContext,
) {
}
public function applyToItem(
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
array $identifiers,
?Operation $operation = null,
array $context = [],
): void {
if (!is_a($resourceClass, PaymentRequestInterface::class, true)) {
return;
}
if (!$this->sectionProvider->getSection() instanceof ShopApiSection) {
return;
}
$rootAlias = $queryBuilder->getRootAliases()[0];
$paymentJoin = $queryNameGenerator->generateJoinAlias('payment');
$orderJoin = $queryNameGenerator->generateJoinAlias('order');
$customerJoin = $queryNameGenerator->generateJoinAlias('customer');
$userJoin = $queryNameGenerator->generateJoinAlias('user');
$createdByGuestParameterName = $queryNameGenerator->generateParameterName('createdByGuest');
$queryBuilder
->innerJoin(sprintf('%s.payment', $rootAlias), $paymentJoin)
->innerJoin(sprintf('%s.order', $paymentJoin), $orderJoin)
->leftJoin(sprintf('%s.customer', $orderJoin), $customerJoin)
->leftJoin(sprintf('%s.user', $customerJoin), $userJoin);
$user = $this->userContext->getUser();
if ($user instanceof ShopUserInterface) {
$customerParam = $queryNameGenerator->generateParameterName('customer');
$queryBuilder
->andWhere($queryBuilder->expr()->eq(sprintf('%s.customer', $orderJoin), sprintf(':%s', $customerParam)))
->setParameter($customerParam, $user->getCustomer());
return;
}
$queryBuilder
->andWhere(
$queryBuilder->expr()->orX(
$queryBuilder->expr()->isNull($userJoin),
$queryBuilder->expr()->isNull(sprintf('%s.customer', $orderJoin)),
$queryBuilder->expr()->andX(
$queryBuilder->expr()->isNotNull($userJoin),
$queryBuilder->expr()->eq(sprintf('%s.createdByGuest', $orderJoin), sprintf(':%s', $createdByGuestParameterName)),
),
),
)
->setParameter($createdByGuestParameterName, true);
}
}
Conclusion
The vulnerability CVE-2026-53639 in Sylius exposes payment request APIs to unauthorized access due to a lack of ownership checks. It is crucial to update to the patched versions or implement the provided workarounds to mitigate the risks associated with this vulnerability.
See every vulnerability recorded for sylius/sylius →
FAQ
CVE-2026-53639 is a vulnerability in the Sylius eCommerce platform that allows unauthorized access to payment request information due to insufficient ownership checks.
An attacker can read sensitive order details and modify payment request payloads, potentially redirecting users to malicious sites.
You can use Vulert, which monitors open-source vulnerabilities in your software. Visit Vulert Scanner to check your application without needing to sign up.
Versions 2.0.0 to 2.0.17, 2.1.0 to 2.1.14, and 2.2.0 to 2.2.5 are affected by this vulnerability.
The CVSS score of this vulnerability is 6.3, indicating a moderate severity level.
References
Related vulnerabilities
Recent vulnerabilities recorded for sylius/sylius.