From b42c86360beb12e8f6399370438ccad58b1e8c8b Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Mon, 2 Feb 2026 12:05:33 -0600 Subject: [PATCH] fix(#190,#191): fix XSS vulnerabilities in Mermaid and WikiLink rendering CRITICAL SECURITY FIXES for two XSS vulnerabilities Mermaid XSS Fix (#190): - Changed securityLevel from "loose" to "strict" - Disabled htmlLabels to prevent HTML injection - Blocks script execution and event handlers in SVG output WikiLink XSS Fix (#191): - Added alphanumeric whitelist validation for slugs - Escape HTML entities in title attribute - Reject slugs with special characters that could break attributes - Return escaped text for invalid slugs Security Impact: - Prevents account takeover via cookie theft - Blocks malicious script execution in user browsers - Enforces strict content security for user-provided content Fixes #190, #191 Co-Authored-By: Claude Sonnet 4.5 --- apps/web/src/components/knowledge/WikiLinkRenderer.tsx | 10 ++++++++-- apps/web/src/components/mindmap/MermaidViewer.tsx | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/knowledge/WikiLinkRenderer.tsx b/apps/web/src/components/knowledge/WikiLinkRenderer.tsx index aad0b63..25b5400 100644 --- a/apps/web/src/components/knowledge/WikiLinkRenderer.tsx +++ b/apps/web/src/components/knowledge/WikiLinkRenderer.tsx @@ -56,14 +56,20 @@ function parseWikiLinks(html: string): string { const trimmedSlug = slug.trim(); const text = displayText?.trim() ?? trimmedSlug; + // Validate slug contains only safe characters + if (!/^[a-zA-Z0-9\-_./]+$/.test(trimmedSlug)) { + // Invalid slug - return original text without creating a link + return escapeHtml(match); + } + // Create a styled link // Using data-wiki-link attribute for styling and click handling - return `${escapeHtml(text)}`; }); } diff --git a/apps/web/src/components/mindmap/MermaidViewer.tsx b/apps/web/src/components/mindmap/MermaidViewer.tsx index a45aedf..41568a9 100644 --- a/apps/web/src/components/mindmap/MermaidViewer.tsx +++ b/apps/web/src/components/mindmap/MermaidViewer.tsx @@ -36,10 +36,10 @@ export function MermaidViewer({ theme: isDark ? "dark" : "default", flowchart: { useMaxWidth: true, - htmlLabels: true, + htmlLabels: false, curve: "basis", }, - securityLevel: "loose", + securityLevel: "strict", }); // Generate unique ID for this render