CVE-2026-31823: Sylius/sylius Cross-Site Scripting Vulnerability

MODERATE
Advisory Identifier: GHSA-mx4q-xxc9-pf5q
CVSS 4.8
CWE-79
Published
Advisory Summary

CVE-2026-31823 is a MODERATE (CVSS 4.8) cross-site scripting vulnerability (CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')) affecting Sylius/sylius libraries in the Packagist ecosystem. The issue involves sylius vulnerable to authenticated stored xss. Remediation is available by upgrading affected packages to version 2.0.16, 2.1.12, 2.2.3.

CVE-2026-31823 at a Glance

CVE Identifier CVE-2026-31823
GHSA Identifier GHSA-mx4q-xxc9-pf5q
Severity MODERATE
CVSS v3.1 Base Score 4.8
CWE Classification CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Affected Product Sylius/sylius
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 4.8

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required High (PR:H)
User Interaction Required (UI:R)
Scope Changed (S:C)
Confidentiality Low (C:L)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-31823

To remediate this vulnerability, upgrade all affected Sylius/sylius dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

sylius/sylius fixed: 2.0.16
Upgrade sylius/sylius to 2.0.16
sylius/sylius fixed: 2.1.12
Upgrade sylius/sylius to 2.1.12
sylius/sylius fixed: 2.2.3
Upgrade sylius/sylius to 2.2.3
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for sylius/sylius

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-31823, inspect your project dependencies for Sylius/sylius:

inspect dependencies for sylius/sylius

Analyze the terminal output to locate any version of Sylius/sylius in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.0.16), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'), where the product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users. In Sylius/sylius, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Impact An authenticated stored cross-site scripting (XSS) vulnerability exists in multiple places across the shop frontend and admin panel due to unsanitized entity names being rendered as raw HTML. **Shop breadcrumbs** (`shared/breadcrumbs.html.twig`): The `breadcrumbs` macro uses the Twig `|raw` filter on label values. Since taxon names, product names, and ancestor names flow directly into these labels, a malicious taxon name like `<img src=x onerror=alert('XSS')>` is rendered and executed as JavaScript on the storefront. **Admin product taxon picker** (`ProductTaxonTreeController.js`): The `rowRenderer` method interpolates `${name}` directly into a template literal building HTML, allowing script injection through taxon names in the admin panel. **Admin autocomplete fields** (Tom Select): Dropdown items and options render entity names as raw HTML without escaping, allowing XSS through any autocomplete field displaying entity names. An **authenticated administrator** can inject arbitrary HTML or JavaScript via entity names (e.g. taxon name) that is persistently rendered for all users. ### Patches The issue is fixed in versions: 2.0.16, 2.1.12, 2.2.3 and above. ### Workarounds Override vulnerable templates and JavaScript controllers at the project level. --- #### Step 1 — Override shop breadcrumbs template `templates/bundles/SyliusShopBundle/shared/breadcrumbs.html.twig`: ```twig {% macro breadcrumbs(items) %} <ol class="breadcrumb" aria-label="breadcrumbs"> {% for item in items %} <li class="breadcrumb-item fw-normal{{ item.active is defined and item.active ? ' active' }}"> {% if item.path is defined %} <a class="link-reset" href="{{ item.path }}" {{ item.test_attribute is defined ? sylius_test_html_attribute(item.test_attribute) }}>{{ item.label }}</a> {% else %} <span class="text-body-tertiary text-break" {{ item.test_attribute is defined ? sylius_test_html_attribute(item.test_attribute) }}>{{ item.label }}</span> {% endif %} </li> {% endfor %} </ol> {% endmacro %} ``` #### Step 2 — Override order breadcrumbs template `templates/bundles/SyliusShopBundle/account/order/show/content/breadcrumbs.html.twig`: ```twig {% from '@SyliusShop/shared/breadcrumbs.html.twig' import breadcrumbs as breadcrumbs %} {% set order = hookable_metadata.context.order %} <div class="col-12"> {{ breadcrumbs([ { label: 'sylius.ui.home'|trans, path: path('sylius_shop_homepage')}, { label: 'sylius.ui.my_account'|trans, path: path('sylius_shop_account_dashboard')}, { label: 'sylius.ui.order_history'|trans, path: path('sylius_shop_account_order_index')}, { label: '#'~order.number, active: true, test_attribute: 'order-number' } ]) }} </div> ``` #### Step 3 — Override ProductTaxonTreeController.js Disable the vendor controller in `assets/admin/controllers.json`: ```diff "product-taxon-tree": { - "enabled": true, + "enabled": false, "fetch": "lazy" }, ``` Create `assets/admin/controllers/product_taxon_tree_controller.js` — copy the original from `vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/assets/controllers/ProductTaxonTreeController.js` and apply the following change: ```diff + const escapeHtml = (str) => { + const div = document.createElement('div'); + div.textContent = str; + return div.innerHTML; + }; // in rowRenderer: - <span class="infinite-tree-title">${name}</span> + <span class="infinite-tree-title">${escapeHtml(name)}</span> ``` Register the patched controller in `assets/admin/bootstrap.js`: ```js import ProductTaxonTreeController from './controllers/product_taxon_tree_controller'; app.register('sylius--admin-bundle--product-taxon-tree', ProductTaxonTreeController); ``` #### Step 4 — Add autocomplete XSS protection `assets/admin/scripts/autocomplete-xss-protection.js`: ```js const escapeHtml = (str) => { if (typeof str !== 'string') return str; const div = document.createElement('div'); div.textContent = str; return div.innerHTML; }; document.addEventListener('autocomplete:pre-connect', (event) => { const options = event.detail.options; if (!options.render) return; const labelField = options.labelField || 'text'; const wrapRenderer = (renderer) => { if (!renderer) return renderer; return (data, escape) => { const escaped = { ...data }; if (escaped[labelField]) { escaped[labelField] = escapeHtml(escaped[labelField]); } return renderer(escaped, escape); }; }; if (options.render.item) options.render.item = wrapRenderer(options.render.item); if (options.render.option) options.render.option = wrapRenderer(options.render.option); }); ``` Import in `assets/admin/entrypoint.js` **before** bootstrap: ```diff + import './scripts/autocomplete-xss-protection'; import './bootstrap.js'; ``` #### Step 5 — Rebuild assets ```bash yarn encore dev # or: yarn encore production ``` ### Reporters We would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability: - Djibril Mounkoro (@whiteov3rflow) - Bartłomiej Nowiński (@bnBart) ### For more information If you have any questions or comments about this advisory: - Open an issue in [Sylius issues](https://github.com/Sylius/Sylius/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen) - Email us at [security@sylius.com](mailto:security@sylius.com)

CVE-2026-31823 Affected Sylius/sylius Versions

3 component(s)
Fixed Versions:
2.0.162.1.122.2.3
Product / Package Ecosystem Affected Versions Fixed Version
sylius/sylius
Packagist
≥ 2.0.0
< 2.0.16
2.0.16
sylius/sylius
Packagist
≥ 2.1.0
< 2.1.12
2.1.12
sylius/sylius
Packagist
≥ 2.2.0
< 2.2.3
2.2.3

References

Frequently Asked Questions

What is CVE-2026-31823?
CVE-2026-31823 is a security vulnerability in Sylius/sylius involving Sylius Vulnerable to Authenticated Stored XSS under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').
Which Sylius/sylius versions are affected?
Affected versions include releases prior to 2.0.16, 2.1.12, 2.2.3 across affected packages: sylius/sylius.
What version fixes CVE-2026-31823?
Upgrading to 2.0.16, 2.1.12, 2.2.3 (or the latest patched release for your respective branch) resolves the vulnerability.
Is sylius/sylius affected?
Yes, sylius/sylius is affected in releases prior to 2.0.16, 2.1.12, 2.2.3. Upgrade your dependency to 2.0.16, 2.1.12, 2.2.3 or later.
What is the CVSS score of CVE-2026-31823?
CVE-2026-31823 has a CVSS v3.1 base score of 4.8 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N.
What CWE is associated with CVE-2026-31823?
CVE-2026-31823 is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.).
How can I check Packagist dependencies for CVE-2026-31823?
Run the dependency tree command: 'inspect dependencies for sylius/sylius'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-mx4q-xxc9-pf5q",
  "modified" : "2026-03-11T20:33:00Z",
  "published" : "2026-03-11T00:13:20Z",
  "aliases" : [ "CVE-2026-31823" ],
  "summary" : "Sylius Vulnerable to Authenticated Stored XSS",
  "details" : "### Impact\n\nAn authenticated stored cross-site scripting (XSS) vulnerability exists in multiple places across the shop frontend and admin panel due to unsanitized entity names being rendered as raw HTML.\n\n**Shop breadcrumbs** (`shared/breadcrumbs.html.twig`): The `breadcrumbs` macro uses the Twig `|raw` filter on label values. Since taxon names, product names, and ancestor names flow directly into these labels, a malicious taxon name like `<img src=x onerror=alert('XSS')>` is rendered and executed as JavaScript on the storefront.\n\n**Admin product taxon picker** (`ProductTaxonTreeController.js`): The `rowRenderer` method interpolates `${name}` directly into a template literal building HTML, allowing script injection through taxon names in the admin panel.\n\n**Admin autocomplete fields** (Tom Select): Dropdown items and options render entity names as raw HTML without escaping, allowing XSS through any autocomplete field displaying entity names.\n\nAn **authenticated administrator** can inject arbitrary HTML or JavaScript via entity names (e.g. taxon name) that is persistently rendered for all users.\n\n### Patches\n\nThe issue is fixed in versions: 2.0.16, 2.1.12, 2.2.3 and above.\n\n### Workarounds\n\nOverride vulnerable templates and JavaScript controllers at the project level.\n\n---\n\n#### Step 1 — Override shop breadcrumbs template\n\n`templates/bundles/SyliusShopBundle/shared/breadcrumbs.html.twig`:\n\n```twig\n{% macro breadcrumbs(items) %}\n    <ol class=\"breadcrumb\" aria-label=\"breadcrumbs\">\n        {% for item in items %}\n            <li class=\"breadcrumb-item fw-normal{{ item.active is defined and item.active ? ' active' }}\">\n                {% if item.path is defined %}\n                    <a class=\"link-reset\" href=\"{{ item.path }}\" {{ item.test_attribute is defined ? sylius_test_html_attribute(item.test_attribute) }}>{{ item.label }}</a>\n                {% else %}\n                    <span class=\"text-body-tertiary text-break\" {{ item.test_attribute is defined ? sylius_test_html_attribute(item.test_attribute) }}>{{ item.label }}</span>\n                {% endif %}\n            </li>\n        {% endfor %}\n    </ol>\n{% endmacro %}\n```\n\n#### Step 2 — Override order breadcrumbs template\n\n`templates/bundles/SyliusShopBundle/account/order/show/content/breadcrumbs.html.twig`:\n\n```twig\n{% from '@SyliusShop/shared/breadcrumbs.html.twig' import breadcrumbs as breadcrumbs %}\n\n{% set order = hookable_metadata.context.order %}\n\n<div class=\"col-12\">\n    {{ breadcrumbs([\n        { label: 'sylius.ui.home'|trans, path: path('sylius_shop_homepage')},\n        { label: 'sylius.ui.my_account'|trans, path: path('sylius_shop_account_dashboard')},\n        { label: 'sylius.ui.order_history'|trans, path: path('sylius_shop_account_order_index')},\n        { label: '#'~order.number, active: true, test_attribute: 'order-number' }\n    ]) }}\n</div>\n```\n\n#### Step 3 — Override ProductTaxonTreeController.js\n\nDisable the vendor controller in `assets/admin/controllers.json`:\n\n```diff\n  \"product-taxon-tree\": {\n-   \"enabled\": true,\n+   \"enabled\": false,\n    \"fetch\": \"lazy\"\n  },\n```\n\nCreate `assets/admin/controllers/product_taxon_tree_controller.js` — copy the original from `vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/assets/controllers/ProductTaxonTreeController.js` and apply the following change:\n\n```diff\n+ const escapeHtml = (str) => {\n+     const div = document.createElement('div');\n+     div.textContent = str;\n+     return div.innerHTML;\n+ };\n\n  // in rowRenderer:\n- <span class=\"infinite-tree-title\">${name}</span>\n+ <span class=\"infinite-tree-title\">${escapeHtml(name)}</span>\n```\n\nRegister the patched controller in `assets/admin/bootstrap.js`:\n\n```js\nimport ProductTaxonTreeController from './controllers/product_taxon_tree_controller';\napp.register('sylius--admin-bundle--product-taxon-tree', ProductTaxonTreeController);\n```\n\n#### Step 4 — Add autocomplete XSS protection\n\n`assets/admin/scripts/autocomplete-xss-protection.js`:\n\n```js\nconst escapeHtml = (str) => {\n    if (typeof str !== 'string') return str;\n    const div = document.createElement('div');\n    div.textContent = str;\n    return div.innerHTML;\n};\n\ndocument.addEventListener('autocomplete:pre-connect', (event) => {\n    const options = event.detail.options;\n    if (!options.render) return;\n\n    const labelField = options.labelField || 'text';\n    const wrapRenderer = (renderer) => {\n        if (!renderer) return renderer;\n        return (data, escape) => {\n            const escaped = { ...data };\n            if (escaped[labelField]) {\n                escaped[labelField] = escapeHtml(escaped[labelField]);\n            }\n            return renderer(escaped, escape);\n        };\n    };\n\n    if (options.render.item) options.render.item = wrapRenderer(options.render.item);\n    if (options.render.option) options.render.option = wrapRenderer(options.render.option);\n});\n```\n\nImport in `assets/admin/entrypoint.js` **before** bootstrap:\n\n```diff\n+ import './scripts/autocomplete-xss-protection';\n  import './bootstrap.js';\n```\n\n#### Step 5 — Rebuild assets\n\n```bash\nyarn encore dev  # or: yarn encore production\n```\n\n### Reporters\n\nWe would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability:\n- Djibril Mounkoro (@whiteov3rflow)\n- Bartłomiej Nowiński (@bnBart)\n\n### For more information\n\nIf you have any questions or comments about this advisory:\n\n- Open an issue in [Sylius issues](https://github.com/Sylius/Sylius/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen)\n- Email us at [security@sylius.com](mailto:security@sylius.com)",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "sylius/sylius"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.0.0"
      }, {
        "fixed" : "2.0.16"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.0.15"
    }
  }, {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "sylius/sylius"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.1.0"
      }, {
        "fixed" : "2.1.12"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.1.11"
    }
  }, {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "sylius/sylius"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.2.0"
      }, {
        "fixed" : "2.2.3"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.2.2"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/Sylius/Sylius/security/advisories/GHSA-mx4q-xxc9-pf5q"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-31823"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/Sylius/Sylius"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-79" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-03-11T00:13:20Z",
    "nvd_published_at" : "2026-03-10T22:16:19Z"
  }
}