{"id":"GHSA-mx4q-xxc9-pf5q","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 `\u003cimg src=x onerror=alert('XSS')\u003e` 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    \u003col class=\"breadcrumb\" aria-label=\"breadcrumbs\"\u003e\n        {% for item in items %}\n            \u003cli class=\"breadcrumb-item fw-normal{{ item.active is defined and item.active ? ' active' }}\"\u003e\n                {% if item.path is defined %}\n                    \u003ca class=\"link-reset\" href=\"{{ item.path }}\" {{ item.test_attribute is defined ? sylius_test_html_attribute(item.test_attribute) }}\u003e{{ item.label }}\u003c/a\u003e\n                {% else %}\n                    \u003cspan class=\"text-body-tertiary text-break\" {{ item.test_attribute is defined ? sylius_test_html_attribute(item.test_attribute) }}\u003e{{ item.label }}\u003c/span\u003e\n                {% endif %}\n            \u003c/li\u003e\n        {% endfor %}\n    \u003c/ol\u003e\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\u003cdiv class=\"col-12\"\u003e\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\u003c/div\u003e\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) =\u003e {\n+     const div = document.createElement('div');\n+     div.textContent = str;\n+     return div.innerHTML;\n+ };\n\n  // in rowRenderer:\n- \u003cspan class=\"infinite-tree-title\"\u003e${name}\u003c/span\u003e\n+ \u003cspan class=\"infinite-tree-title\"\u003e${escapeHtml(name)}\u003c/span\u003e\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) =\u003e {\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) =\u003e {\n    const options = event.detail.options;\n    if (!options.render) return;\n\n    const labelField = options.labelField || 'text';\n    const wrapRenderer = (renderer) =\u003e {\n        if (!renderer) return renderer;\n        return (data, escape) =\u003e {\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)","aliases":["CVE-2026-31823"],"modified":"2026-03-13T10:56:24.260023Z","published":"2026-03-11T00:13:20Z","database_specific":{"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-03-11T00:13:20Z","nvd_published_at":"2026-03-10T22:16:19Z","cwe_ids":["CWE-79"]},"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"}],"affected":[{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0"},{"fixed":"2.0.16"}]}],"versions":["v2.0.0","v2.0.1","v2.0.10","v2.0.11","v2.0.12","v2.0.13","v2.0.14","v2.0.15","v2.0.2","v2.0.3","v2.0.4","v2.0.5","v2.0.6","v2.0.7","v2.0.8","v2.0.9"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.0.15","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-mx4q-xxc9-pf5q/GHSA-mx4q-xxc9-pf5q.json"}},{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.1.0"},{"fixed":"2.1.12"}]}],"versions":["v2.1.0","v2.1.1","v2.1.10","v2.1.11","v2.1.2","v2.1.3","v2.1.4","v2.1.5","v2.1.6","v2.1.7","v2.1.8","v2.1.9"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.1.11","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-mx4q-xxc9-pf5q/GHSA-mx4q-xxc9-pf5q.json"}},{"package":{"name":"sylius/sylius","ecosystem":"Packagist","purl":"pkg:composer/sylius/sylius"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.2.0"},{"fixed":"2.2.3"}]}],"versions":["v2.2.0","v2.2.1","v2.2.2"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.2.2","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-mx4q-xxc9-pf5q/GHSA-mx4q-xxc9-pf5q.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N"}]}