/** * Mermaid SVG sanitizer security spec: the rendered diagram must never * carry an executable surface into the markdown preview — foreignObject * (the raw-HTML channel) is stripped wholesale, event/`@*` attributes are * removed, href/xlink:href are removed, script elements are removed, and a * malformed/foreign document is rejected entirely (empty string) rather * than passed through. */ // @vitest-environment jsdom import { describe, expect, it } from 'vitest' import { sanitizeSvg } from '../src/client/mermaid-sanitize.ts' describe('sanitizeSvg', () => { it('keeps a benign diagram (svg + text nodes)', () => { const svg = 'Hello' const out = sanitizeSvg(svg) expect(out).toContain('Hello') expect(out).not.toContain('foreignObject') }) it('strips foreignObject wholesale (the raw-HTML channel)', () => { const svg = [ '', '
', 'keep', '
', ].join('') const out = sanitizeSvg(svg) expect(out).not.toContain('foreignObject') expect(out).not.toContain('keep') }) it('strips on* and @* attributes from every element', () => { const svg = 't' const out = sanitizeSvg(svg) expect(out).not.toContain('onload') expect(out).not.toContain('onclick') expect(out).not.toContain('@click') }) it('strips mixed-case event/link attributes (HTML parsing normalizes case)', () => { const svg = [ '', 't', 'x', 'u', '', ].join('') const out = sanitizeSvg(svg) expect(out).not.toContain('oNload') expect(out).not.toContain('OnClick') expect(out).not.toContain('@Click') expect(out).not.toContain('HREF') expect(out).not.toContain('xlink:HREF') expect(out).not.toContain('javascript:') }) it('removes href and xlink:href regardless of scheme', () => { const svg = [ '', 'x', 'y', '', ].join('') const out = sanitizeSvg(svg) expect(out).not.toContain('href') expect(out).not.toContain('javascript:') expect(out).not.toContain('data:text/html') }) it('removes script elements', () => { const svg = 't' const out = sanitizeSvg(svg) expect(out).not.toContain('script') expect(out).toContain('t') }) it('strips mixed-case element names (HTML parsing normalizes tag casing)', () => { const svg = [ '', '', '
', '
', '