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 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-02 12:05:33 -06:00
parent 680d75f910
commit b42c86360b
2 changed files with 10 additions and 4 deletions

View File

@@ -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 `<a
return `<a
href="/knowledge/${encodeURIComponent(trimmedSlug)}"
data-wiki-link="true"
data-slug="${encodeURIComponent(trimmedSlug)}"
class="wiki-link text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline decoration-dotted hover:decoration-solid transition-colors"
title="Go to ${trimmedSlug}"
title="Go to ${escapeHtml(trimmedSlug)}"
>${escapeHtml(text)}</a>`;
});
}

View File

@@ -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