CVE-2026-31825
Sylius has a DQL Injection via API Order Filters
Sylius is an Open Source eCommerce Framework on Symfony. Sylius API filters ProductPriceOrderFilter and TranslationOrderNameAndLocaleFilter pass user-supplied order direction values directly to Doctrine's orderBy() without validation. An attacker can inject arbitrary DQL. The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- Low
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
5.3
Sylius has a DQL Injection via API Order Filters
Sylius is an Open Source eCommerce Framework on Symfony. Sylius API filters ProductPriceOrderFilter and TranslationOrderNameAndLocaleFilter pass user-supplied order direction values directly to Doctrine's orderBy() without validation. An attacker can inject arbitrary DQL. The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
- Record
CVE-2026-31825- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-89, CWE-943
- Updated
- 2026-11-02
EUVDEUVD-2026-10923
5.3
Sylius is an Open Source eCommerce Framework on Symfony. Sylius API filters ProductPriceOrderFilter and TranslationOrderNameAndLocaleFilter pass user-supplied order direction values directly to Doctrine's orderBy() without validation. An attacker can inject arbitrary DQL. The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
- Record
EUVD-2026-10923- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-xcwx-r2gw-w93m
5.3
Sylius has a DQL Injection via API Order Filters
Impact
Sylius API filters ProductPriceOrderFilter and TranslationOrderNameAndLocaleFilter pass user-supplied order direction values directly to Doctrine's orderBy() without validation. An attacker can inject arbitrary DQL:
GET /api/v2/shop/products?order[price]=ASC,%20variant.code%20DESC
Patches
The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
Workarounds
An EventSubscriber that sanitizes order query parameters only on API routes before they reach the vulnerable filters.
The subscriber accepts an $apiRoute constructor parameter (default /api/v2) and skips non-API requests entirely — so there is zero overhead on shop/admin page requests.
This follows the same pattern used by Sylius's own KernelRequestEventSubscriber (src/Sylius/Bundle/ApiBundle/EventSubscriber/KernelRequestEventSubscriber.php), which also uses str_contains($pathInfo, $this->apiRoute) to scope logic to API routes.
Step 1 — Create the EventSubscriber
src/EventSubscriber/SanitizeOrderDirectionSubscriber.php:
<?php
declare(strict_types=1);
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
final class SanitizeOrderDirectionSubscriber implements EventSubscriberInterface
{
private const ALLOWED_DIRECTIONS = ['asc', 'desc'];
public function __construct(
private string $apiRoute,
) {
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['sanitizeOrderParameters', 64],
];
}
public function sanitizeOrderParameters(RequestEvent $event): void
{
if (!str_contains($event->getRequest()->getPathInfo(), $this->apiRoute)) {
return;
}
$request = $event->getRequest();
/** @var mixed $order */
$order = $request->query->all()['order'] ?? null;
if (!is_array($order)) {
return;
}
$needsSanitization = false;
$sanitized = [];
foreach ($order as $field => $direction) {
if (is_string($direction) && in_array(strtolower($direction), self::ALLOWED_DIRECTIONS, true)) {
$sanitized[$field] = $direction;
} else {
$needsSanitization = true;
}
}
if (!$needsSanitization) {
return;
}
$all = $request->query->all();
$all['order'] = $sanitized;
$request->query->replace($all);
$request->server->set('QUERY_STRING', http_build_query($all));
$request->attributes->set('_api_filters', $all);
}
}
Step 2 — Register the service
Option A — If your config/services.yaml already has App\ autowiring (Symfony default):
# Nothing to do — autoconfigure picks up EventSubscriberInterface automatically.
# Optionally bind the API route prefix:
services:
App\EventSubscriber\SanitizeOrderDirectionSubscriber:
arguments:
$apiRoute: '%sylius.security.new_api_route%'
Option B — If there is no App\ autowiring:
services:
App\EventSubscriber\SanitizeOrderDirectionSubscriber:
arguments:
$apiRoute: '%sylius.security.new_api_route%'
tags: ['kernel.event_subscriber']
Using %sylius.security.new_api_route% ties the subscriber to the same prefix Sylius uses (/api/v2 by default). If the parameter is not available, hardcode '/api/v2' instead.
Step 3 — Clear cache
bin/console cache:clear
Reporters
We would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability:
- Chris Alupului (@Neosprings)
- Bartłomiej Nowiński (@bnBart)
For more information
If you have…
- Record
GHSA-xcwx-r2gw-w93m- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-89, CWE-943
- Updated
- 2026-11-02
NVD
5.3
Sylius is an Open Source eCommerce Framework on Symfony. Sylius API filters ProductPriceOrderFilter and TranslationOrderNameAndLocaleFilter pass user-supplied order direction values directly to Doctrine's orderBy() without validation. An attacker can inject arbitrary DQL. The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
- Record
CVE-2026-31825- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-89, CWE-943
- Updated
- 2026-11-02
OSV
5.3
Sylius has a DQL Injection via API Order Filters
Sylius is an Open Source eCommerce Framework on Symfony. Sylius API filters ProductPriceOrderFilter and TranslationOrderNameAndLocaleFilter pass user-supplied order direction values directly to Doctrine's orderBy() without validation. An attacker can inject arbitrary DQL. The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
- Record
CVE-2026-31825- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-89, CWE-943
- Updated
- 2026-11-02
OSVGHSA-xcwx-r2gw-w93m
5.3
Sylius has a DQL Injection via API Order Filters
Impact
Sylius API filters ProductPriceOrderFilter and TranslationOrderNameAndLocaleFilter pass user-supplied order direction values directly to Doctrine's orderBy() without validation. An attacker can inject arbitrary DQL:
GET /api/v2/shop/products?order[price]=ASC,%20variant.code%20DESC
Patches
The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
Workarounds
An EventSubscriber that sanitizes order query parameters only on API routes before they reach the vulnerable filters.
The subscriber accepts an $apiRoute constructor parameter (default /api/v2) and skips non-API requests entirely — so there is zero overhead on shop/admin page requests.
This follows the same pattern used by Sylius's own KernelRequestEventSubscriber (src/Sylius/Bundle/ApiBundle/EventSubscriber/KernelRequestEventSubscriber.php), which also uses str_contains($pathInfo, $this->apiRoute) to scope logic to API routes.
Step 1 — Create the EventSubscriber
src/EventSubscriber/SanitizeOrderDirectionSubscriber.php:
<?php
declare(strict_types=1);
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
final class SanitizeOrderDirectionSubscriber implements EventSubscriberInterface
{
private const ALLOWED_DIRECTIONS = ['asc', 'desc'];
public function __construct(
private string $apiRoute,
) {
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['sanitizeOrderParameters', 64],
];
}
public function sanitizeOrderParameters(RequestEvent $event): void
{
if (!str_contains($event->getRequest()->getPathInfo(), $this->apiRoute)) {
return;
}
$request = $event->getRequest();
/** @var mixed $order */
$order = $request->query->all()['order'] ?? null;
if (!is_array($order)) {
return;
}
$needsSanitization = false;
$sanitized = [];
foreach ($order as $field => $direction) {
if (is_string($direction) && in_array(strtolower($direction), self::ALLOWED_DIRECTIONS, true)) {
$sanitized[$field] = $direction;
} else {
$needsSanitization = true;
}
}
if (!$needsSanitization) {
return;
}
$all = $request->query->all();
$all['order'] = $sanitized;
$request->query->replace($all);
$request->server->set('QUERY_STRING', http_build_query($all));
$request->attributes->set('_api_filters', $all);
}
}
Step 2 — Register the service
Option A — If your config/services.yaml already has App\ autowiring (Symfony default):
# Nothing to do — autoconfigure picks up EventSubscriberInterface automatically.
# Optionally bind the API route prefix:
services:
App\EventSubscriber\SanitizeOrderDirectionSubscriber:
arguments:
$apiRoute: '%sylius.security.new_api_route%'
Option B — If there is no App\ autowiring:
services:
App\EventSubscriber\SanitizeOrderDirectionSubscriber:
arguments:
$apiRoute: '%sylius.security.new_api_route%'
tags: ['kernel.event_subscriber']
Using %sylius.security.new_api_route% ties the subscriber to the same prefix Sylius uses (/api/v2 by default). If the parameter is not available, hardcode '/api/v2' instead.
Step 3 — Clear cache
bin/console cache:clear
Reporters
We would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability:
- Chris Alupului (@Neosprings)
- Bartłomiej Nowiński (@bnBart)
For more information
If you have…
- Record
GHSA-xcwx-r2gw-w93m- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-89, CWE-943
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
sylius/syliusPackagist |
through 1.9.11 | 1.9.12 |
sylius/syliusPackagist |
1.10.0 to 1.10.15 | 1.10.16 |
sylius/syliusPackagist |
1.11.0 to 1.11.16 | 1.11.17 |
sylius/syliusPackagist |
1.12.0 to 1.12.22 | 1.12.23 |
sylius/syliusPackagist |
1.13.0 to 1.13.14 | 1.13.15 |
sylius/syliusPackagist |
1.14.0 to 1.14.17 | 1.14.18 |
sylius/syliusPackagist |
2.0.0 to 2.0.15 | 2.0.16 |
sylius/syliusPackagist |
2.1.0 to 2.1.11 | 2.1.12 |
sylius/syliusPackagist |
2.2.0 to 2.2.2 | 2.2.3 |
sylius/syliusPackagist |
before 1.9.12, plus listed versions v0.1.0v0.10.0v0.11.0v0.12.0v0.13.0 Show 45 moreShow lessv0.14.0v0.15.0v0.16.0v0.17.0v0.18.0v0.19.0v0.2.0v0.3.0v0.5.0v0.6.0v0.7.0v0.8.0v0.9.0v1.0.0v1.0.0-alpha.1v1.0.0-alpha.2v1.0.0-beta.1v1.0.0-beta.2v1.0.0-beta.3v1.0.0-rc.1v1.0.0-rc.2v1.0.1v1.0.10v1.0.11v1.0.12v1.0.13v1.0.14v1.0.15v1.0.16v1.0.17v1.0.18v1.0.2v1.0.3v1.0.4v1.0.5v1.0.6v1.0.7v1.0.8v1.0.9v1.1.0v1.1.0-RCv1.1.1v1.1.10v1.1.11v1.1.12 |
1.9.12 |
Show 8 moreShow less
| Package | Affected | Fixed |
|---|---|---|
sylius/syliusPackagist |
1.10.0 up to 1.10.16, plus listed versions v1.10.0v1.10.1v1.10.10v1.10.11v1.10.12 Show 11 moreShow lessv1.10.13v1.10.14v1.10.15v1.10.2v1.10.3v1.10.4v1.10.5v1.10.6v1.10.7v1.10.8v1.10.9 |
1.10.16 |
sylius/syliusPackagist |
1.11.0 up to 1.11.17, plus listed versions v1.11.0v1.11.1v1.11.10v1.11.11v1.11.12 Show 12 moreShow lessv1.11.13v1.11.14v1.11.15v1.11.16v1.11.2v1.11.3v1.11.4v1.11.5v1.11.6v1.11.7v1.11.8v1.11.9 |
1.11.17 |
sylius/syliusPackagist |
1.12.0 up to 1.12.23, plus listed versions v1.12.0v1.12.1v1.12.10v1.12.11v1.12.12 Show 18 moreShow lessv1.12.13v1.12.14v1.12.15v1.12.16v1.12.17v1.12.18v1.12.19v1.12.2v1.12.20v1.12.21v1.12.22v1.12.3v1.12.4v1.12.5v1.12.6v1.12.7v1.12.8v1.12.9 |
1.12.23 |
sylius/syliusPackagist |
1.13.0 up to 1.13.15, plus listed versions v1.13.0v1.13.1v1.13.10v1.13.11v1.13.12 Show 10 moreShow lessv1.13.13v1.13.14v1.13.2v1.13.3v1.13.4v1.13.5v1.13.6v1.13.7v1.13.8v1.13.9 |
1.13.15 |
sylius/syliusPackagist |
1.14.0 up to 1.14.18, plus listed versions v1.14.0v1.14.1v1.14.10v1.14.11v1.14.12 Show 13 moreShow lessv1.14.13v1.14.14v1.14.15v1.14.16v1.14.17v1.14.2v1.14.3v1.14.4v1.14.5v1.14.6v1.14.7v1.14.8v1.14.9 |
1.14.18 |
sylius/syliusPackagist |
2.0.0 up to 2.0.16, plus listed versions v2.0.0v2.0.1v2.0.10v2.0.11v2.0.12 Show 11 moreShow lessv2.0.13v2.0.14v2.0.15v2.0.2v2.0.3v2.0.4v2.0.5v2.0.6v2.0.7v2.0.8v2.0.9 |
2.0.16 |
sylius/syliusPackagist |
2.1.0 up to 2.1.12, plus listed versions v2.1.0v2.1.1v2.1.10v2.1.11v2.1.2 Show 7 moreShow lessv2.1.3v2.1.4v2.1.5v2.1.6v2.1.7v2.1.8v2.1.9 |
2.1.12 |
sylius/syliusPackagist |
2.2.0 up to 2.2.3, plus listed versions v2.2.0v2.2.1v2.2.2 |
2.2.3 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-31825 is a medium vulnerability (CVSS 5.3) in Sylius, published March 10, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.23%, the 13th percentile. Fixed in sylius/sylius 1.9.12.
References
Left out here: 138 versions and the rest of 2 source descriptions. The JSON record has them.