diff --git a/src/channels/web/static/app.js b/src/channels/web/static/app.js index 7ca9a25b..de1f83b6 100644 --- a/src/channels/web/static/app.js +++ b/src/channels/web/static/app.js @@ -676,26 +676,20 @@ function renderMarkdown(text) { return escapeHtml(text); } -// Strip dangerous HTML elements and attributes from rendered markdown. -// This prevents XSS from tool output or prompt injection in LLM responses. +// Sanitize rendered HTML using DOMPurify to prevent XSS from tool output +// or prompt injection in LLM responses. DOMPurify is a DOM-based sanitizer +// that handles all known bypass vectors (SVG onload, newline-split event +// handlers, mutation XSS, etc.) unlike the regex approach it replaces. function sanitizeRenderedHtml(html) { - html = html.replace(/)<[^<]*)*<\/script>/gi, ''); - html = html.replace(/]*>[\s\S]*?<\/iframe>/gi, ''); - html = html.replace(/]*>[\s\S]*?<\/object>/gi, ''); - html = html.replace(/]*\/?>/gi, ''); - html = html.replace(/]*>[\s\S]*?<\/form>/gi, ''); - html = html.replace(/]*>[\s\S]*?<\/style>/gi, ''); - html = html.replace(/]*\/?>/gi, ''); - html = html.replace(/]*\/?>/gi, ''); - html = html.replace(/]*\/?>/gi, ''); - // Remove event handler attributes (onclick, onerror, onload, etc.) - html = html.replace(/\s+on\w+\s*=\s*"[^"]*"/gi, ''); - html = html.replace(/\s+on\w+\s*=\s*'[^']*'/gi, ''); - html = html.replace(/\s+on\w+\s*=\s*[^\s>]+/gi, ''); - // Remove javascript: and data: URLs in href/src attributes - html = html.replace(/(href|src|action)\s*=\s*["']?\s*javascript\s*:/gi, '$1="'); - html = html.replace(/(href|src|action)\s*=\s*["']?\s*data\s*:/gi, '$1="'); - return html; + if (typeof DOMPurify !== 'undefined') { + return DOMPurify.sanitize(html, { + USE_PROFILES: { html: true }, + FORBID_TAGS: ['style', 'script'], + FORBID_ATTR: ['style', 'onerror', 'onload'] + }); + } + // DOMPurify not available (CDN unreachable) — return empty string rather than unsanitized HTML + return ''; } function copyCodeBlock(btn) { diff --git a/src/channels/web/static/index.html b/src/channels/web/static/index.html index 6f21b428..b6dd9d3a 100644 --- a/src/channels/web/static/index.html +++ b/src/channels/web/static/index.html @@ -15,6 +15,11 @@ +