Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐘
🐘 Packagist
Not in CISA KEV
MEDIUM severity

GHSA-xcwx-r2gw-w93m — sylius/sylius

MEDIUM

GHSA-xcwx-r2gw-w93m is a medium-severity (CVSS 5.3) 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 asCVE-2026-31825
Published
Mar 11, 2026
Updated
Mar 13, 2026
Affected
9 pkgs
Patched
9 / 9
Exploits
None indexed
Exploitation data as of Sep 24, 2026 · OSV.dev, 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 GHSA-xcwx-r2gw-w93m.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs23th percentile — riskier than 23% of all scored CVEsHighest risk

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

How urgent is this, really

GHSA-xcwx-r2gw-w93m plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.

Where this sits among everything scored

Of 379,145 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.

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

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 GHSA-xcwx-r2gw-w93m is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-xcwx-r2gw-w93m can be triaged on real exposure rather than presence alone.

Tailored to GHSA-xcwx-r2gw-w93m. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

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 GHSA-xcwx-r2gw-w93m in your dependencies?

O3 Security finds GHSA-xcwx-r2gw-w93m across Packagist dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.

GHSA-xcwx-r2gw-w93m: sylius/sylius | O3 Security