NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐘
🐘 Packagist
Not in CISA KEV
MEDIUM severity

CVE-2026-31825 — sylius

MEDIUM

CVE-2026-31825 is a medium-severity (CVSS 5.3) SQL Injection vulnerability in sylius/sylius. A fix is available for sylius/sylius — see the affected versions and patch details below.

Sylius has a DQL Injection via API Order Filters

Also known asGHSA-xcwx-r2gw-w93m
Published
Updated
Affected
9 pkgs
Patched
9 / 9
Exploits
None indexed
Exploitation data as of Nov 10, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-31825.

EPSS Exploitation Probability

via FIRST.org ↗
0.2%probability of exploitation in next 30 days
Lower Risk+0.02%
Lower risk than most CVEs14th percentile — riskier than 14% of all scored CVEsHighest risk
0.00%0.28%0.55%0.83%0.0%0.2%May 26Sep 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

Where this sits among everything scored

Real-World Exposure

9 pkgs affected
🐘sylius/sylius🐘sylius/sylius🐘sylius/sylius🐘sylius/sylius🐘sylius/sylius🐘sylius/sylius🐘sylius/sylius🐘sylius/sylius+1 more

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.

Description

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 any questions or comments about this advisory:

Affected Packages

9 total 9 fixed
EcosystemPackageVulnerable rangeFix
🐘Packagistsylius/syliusall versions1.9.12composer require sylius/sylius:^1.9.12
🐘Packagistsylius/sylius≥ 1.10.0&&< 1.10.161.10.16composer require sylius/sylius:^1.10.16
🐘Packagistsylius/sylius≥ 1.11.0&&< 1.11.171.11.17composer require sylius/sylius:^1.11.17
🐘Packagistsylius/sylius≥ 1.12.0&&< 1.12.231.12.23composer require sylius/sylius:^1.12.23
🐘Packagistsylius/sylius≥ 1.13.0&&< 1.13.151.13.15composer require sylius/sylius:^1.13.15
🐘Packagistsylius/sylius≥ 1.14.0&&< 1.14.181.14.18composer require sylius/sylius:^1.14.18

Affected Products

1 product · 9 configurations
Application
syliussylius
≥ 2.2.0 && < 2.2.3
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for sylius/sylius, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update sylius/sylius to 1.9.12 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-31825 is resolved across your whole dependency graph.

  3. Workarounds

    Until you can upgrade, make sure every query built from user input uses parameterised statements or a prepared-statement API rather than string concatenation, and reduce the database account's privileges so an injected query cannot read or alter data beyond what the feature needs.

Frequently Asked Questions

### 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 a
O3 Security · Impact-Aware SCA

Is CVE-2026-31825 in your dependencies?

Find it across Packagist, including transitive dependencies.

CVE-2026-31825: sylius — Fixed in 1.9.12