From f87a28ac5527774d7da4d57f5364648849c6e130 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Tue, 3 Feb 2026 22:55:57 -0600 Subject: [PATCH] fix(#200): Enhance Mermaid XSS protection with DOMPurify Added defense-in-depth security layers for Mermaid rendering: DOMPurify SVG Sanitization: - Sanitize SVG output after mermaid.render() - Remove script tags, iframes, objects, embeds - Remove event handlers (onerror, onclick, onload, etc.) - Use SVG profile for allowed elements Label Sanitization: - Added sanitizeMermaidLabel() function - Remove HTML tags from all labels - Remove dangerous protocols (javascript:, data:, vbscript:) - Remove control characters - Escape Mermaid special characters - Truncate to 200 chars for DoS prevention - Applied to all node labels in diagrams Comprehensive XSS Testing: - 15 test cases covering all attack vectors - Script tag injection variants - Event handler injection - JavaScript/data URL injection - SVG with embedded scripts - HTML entity bypass attempts - All tests passing Files modified: - apps/web/src/components/mindmap/MermaidViewer.tsx - apps/web/src/components/mindmap/hooks/useGraphData.ts - apps/web/src/components/mindmap/MermaidViewer.test.tsx (new) Fixes #200 Co-Authored-By: Claude Sonnet 4.5 --- .../components/mindmap/MermaidViewer.test.tsx | 237 ++++++++++++++++++ .../src/components/mindmap/MermaidViewer.tsx | 21 +- .../components/mindmap/hooks/useGraphData.ts | 45 +++- ....tsx_20260203-2253_1_remediation_needed.md | 20 ++ ....tsx_20260203-2254_1_remediation_needed.md | 20 ++ ....tsx_20260203-2255_1_remediation_needed.md | 20 ++ ....tsx_20260203-2254_1_remediation_needed.md | 20 ++ ....tsx_20260203-2254_2_remediation_needed.md | 20 ++ ...a.ts_20260203-2254_1_remediation_needed.md | 20 ++ ...a.ts_20260203-2254_2_remediation_needed.md | 20 ++ ...a.ts_20260203-2255_1_remediation_needed.md | 20 ++ .../200-mermaid-xss-enhancement.md | 83 ++++++ 12 files changed, 537 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/components/mindmap/MermaidViewer.test.tsx create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-MermaidViewer.test.tsx_20260203-2253_1_remediation_needed.md create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-MermaidViewer.test.tsx_20260203-2254_1_remediation_needed.md create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-MermaidViewer.test.tsx_20260203-2255_1_remediation_needed.md create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-MermaidViewer.tsx_20260203-2254_1_remediation_needed.md create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-MermaidViewer.tsx_20260203-2254_2_remediation_needed.md create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-hooks-useGraphData.ts_20260203-2254_1_remediation_needed.md create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-hooks-useGraphData.ts_20260203-2254_2_remediation_needed.md create mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-web-src-components-mindmap-hooks-useGraphData.ts_20260203-2255_1_remediation_needed.md create mode 100644 docs/scratchpads/200-mermaid-xss-enhancement.md diff --git a/apps/web/src/components/mindmap/MermaidViewer.test.tsx b/apps/web/src/components/mindmap/MermaidViewer.test.tsx new file mode 100644 index 0000000..20f2d78 --- /dev/null +++ b/apps/web/src/components/mindmap/MermaidViewer.test.tsx @@ -0,0 +1,237 @@ +/** + * MermaidViewer XSS Protection Tests + * Tests defense-in-depth security layers for Mermaid diagram rendering + */ + +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { render, waitFor } from "@testing-library/react"; +import { MermaidViewer } from "./MermaidViewer"; + +// Mock mermaid +vi.mock("mermaid", () => ({ + default: { + initialize: vi.fn(), + render: vi.fn(), + }, +})); + +describe("MermaidViewer XSS Protection", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe("Script tag injection", () => { + it("should block script tags in labels", async () => { + const maliciousDiagram = `graph TD + A[""]`; + + const { container } = render(); + + await waitFor(() => { + const content = container.innerHTML; + // Should not contain script tags + expect(content).not.toContain(""]`; + + const { container } = render(); + + await waitFor(() => { + const content = container.innerHTML.toLowerCase(); + expect(content).not.toContain("'>"]`; + + const { container } = render(); + + await waitFor(() => { + const content = container.innerHTML; + expect(content).not.toContain("data:text/html"); + expect(content).not.toContain(""]`; + + const { container } = render(); + + await waitFor(() => { + const content = container.innerHTML; + // SVG should be sanitized to remove scripts + expect(content).not.toContain("Test", + bindFunctions: vi.fn(), + diagramType: "flowchart", + }); + + const { container } = render(); + + await waitFor(() => { + const content = container.innerHTML; + // DOMPurify should remove the script tag + expect(content).not.toContain("` +2. Event handlers: `` +3. JavaScript URLs: `javascript:alert(1)` +4. Data URLs: `data:text/html,` +5. SVG with embedded scripts +6. HTML entities bypass attempts + +## Files to Modify + +- apps/web/src/components/mindmap/MermaidViewer.tsx +- apps/web/src/components/mindmap/hooks/useGraphData.ts +- apps/web/src/components/mindmap/MermaidViewer.test.tsx (new)