{"id":"GHSA-xcj9-5m2h-648r","summary":"Mermaid: Improper sanitization of `classDefs` in diagrams leads to CSS injection","details":"### Details\n\nThe state diagram and any other diagram type that routes user-controlled style strings through createCssStyles parser for Mermaid v11.14.0 and earlier captures `classDef` values with an unrestricted regex:\n\n```jison\n// packages/mermaid/src/diagrams/state/parser/stateDiagram.jison:83\n\u003cCLASSDEFID\u003e[^\\n]*   { this.popState(); return 'CLASSDEF_STYLEOPTS' }\n```\n\nThe value passes unsanitized through `addStyleClass()` -\u003e `createCssStyles()` -\u003e `style.innerHTML` (mermaidAPI.ts:418). A `}` in the value closes the generated CSS selector, and everything after becomes a new CSS rule on the page.\n\n### PoC\n\n```\nstateDiagram-v2 \n      classDef x }*{ background-image: url(\"http://media.giphy.com/media/SggILpMXO7Xt6/giphy.gif\")}\n```\n\nLive demo:\n\u003chttps://mermaid.live/edit#pako:eNpFjzFvgzAQhf-KdVNbEcBgMHhtlkqtOnSJKi8ONsYKBmRMlRTx3-skanvTfbp7996t0IxSAYPZC6_2Rmgn7O4rQ00v5nmvWnRG29OKjqI5aTcug9wZK7RiaHH9A4fO-4kliVXSiFibqbvEzWjvnHxo_fI6vR3e6cGXyX2qTcvhcYMItDMSmHeLisAqZ8UVYeUDQhx8p6ziwEIrhTtx4MNVM4nhcxztrywE0h2wVvRzoGWS_z_8rahBKvcckntgmN5OAFvhDIzUNCZZQXCR5nVaZkUEF2BVFpOcEkoxxhUuyRbB980yjStapKHqoKFlhvPtB7BFZEU\u003e\n\n### Patches\n\nThis has been patched in:\n\n- [v11.15.0](https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4011.15.0) (see [e9b0f34d8d82a6260077764ee45e1d7d90957a0f](https://github.com/mermaid-js/mermaid/commit/e9b0f34d8d82a6260077764ee45e1d7d90957a0f))\n- [v10.9.6](https://github.com/mermaid-js/mermaid/releases/tag/v10.9.6) (see [8fead23c59166b7bab6a39eac81acebee2859102](https://github.com/mermaid-js/mermaid/commit/8fead23c59166b7bab6a39eac81acebee2859102))\n\n### Workarounds\n\nSetting [`\"securityLevel\": \"sandbox\"`](https://mermaid.js.org/config/schema-docs/config.html#securitylevel)  will prevent this, by rendering the mermaid diagram in a sandboxed `\u003ciframe\u003e`.\n\n### Impact\n\n Enables page defacement, user tracking via `url()` callbacks, and DOM attribute exfiltration via CSS `:has()` selectors.","aliases":["CVE-2026-41148"],"modified":"2026-05-11T19:49:01.357085Z","published":"2026-05-11T19:36:41Z","database_specific":{"nvd_published_at":null,"github_reviewed":true,"cwe_ids":["CWE-94"],"github_reviewed_at":"2026-05-11T19:36:41Z","severity":"MODERATE"},"references":[{"type":"WEB","url":"https://github.com/mermaid-js/mermaid/security/advisories/GHSA-xcj9-5m2h-648r"},{"type":"WEB","url":"https://github.com/mermaid-js/mermaid/commit/8fead23c59166b7bab6a39eac81acebee2859102"},{"type":"WEB","url":"https://github.com/mermaid-js/mermaid/commit/e9b0f34d8d82a6260077764ee45e1d7d90957a0f"},{"type":"PACKAGE","url":"https://github.com/mermaid-js/mermaid"},{"type":"WEB","url":"https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4011.15.0"},{"type":"WEB","url":"https://github.com/mermaid-js/mermaid/releases/tag/v10.9.6"},{"type":"WEB","url":"https://mermaid.js.org/config/schema-docs/config.html#securitylevel"}],"affected":[{"package":{"name":"mermaid","ecosystem":"npm","purl":"pkg:npm/mermaid"},"ranges":[{"type":"SEMVER","events":[{"introduced":"11.0.0-alpha.1"},{"fixed":"11.15.0"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-xcj9-5m2h-648r/GHSA-xcj9-5m2h-648r.json","last_known_affected_version_range":"\u003c= 11.14.0"}},{"package":{"name":"mermaid","ecosystem":"npm","purl":"pkg:npm/mermaid"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"10.9.6"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-xcj9-5m2h-648r/GHSA-xcj9-5m2h-648r.json","last_known_affected_version_range":"\u003c= 10.9.5"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:L/SI:L/SA:L"}]}