From 05232f2608ef46533efd5c34c4af5655f9d9f0a6 Mon Sep 17 00:00:00 2001 From: Valerie Liu Date: Thu, 16 Oct 2025 16:39:06 +0100 Subject: [PATCH 1/4] Remove style attributes from markdown-rendered HTML and enhance security - Keep forced styling on images with max-height constraint - Remove dangerous HTML tags (style, link, meta) from markdown output - Improve security sanitization for markdown rendering --- src/lib/ircUtils.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/ircUtils.tsx b/src/lib/ircUtils.tsx index ba606063..a7b36a5b 100644 --- a/src/lib/ircUtils.tsx +++ b/src/lib/ircUtils.tsx @@ -255,6 +255,9 @@ export function renderMarkdown( .replace(/]*>.*?<\/iframe>/gi, "") .replace(/]*>.*?<\/object>/gi, "") .replace(/]*>.*?<\/embed>/gi, "") + .replace(/]*>.*?<\/style>/gi, "") + .replace(/]*\/?>/gi, "") + .replace(/]*\/?>/gi, "") .replace(/on\w+="[^"]*"/gi, "") // Remove event handlers .replace(/javascript:/gi, "#"); From 7c93728b9f9e8fca01328b60494dacc3602d0e50 Mon Sep 17 00:00:00 2001 From: Valerie Liu Date: Thu, 16 Oct 2025 16:48:31 +0100 Subject: [PATCH 2/4] Ensure all img tags have controlled max-height styling - Force all img tags to have style='max-height: 150px;' regardless of source - Override any user-provided styles on images - Maintain consistent image sizing across markdown and raw HTML --- src/lib/ircUtils.tsx | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/lib/ircUtils.tsx b/src/lib/ircUtils.tsx index a7b36a5b..4a71856a 100644 --- a/src/lib/ircUtils.tsx +++ b/src/lib/ircUtils.tsx @@ -249,8 +249,16 @@ export function renderMarkdown( // Parse markdown to HTML const html = marked.parse(text) as string; - // Additional security: remove any remaining script tags or dangerous content that might have slipped through - const sanitizedHtml = html + // Additional security: only allow specific markdown-related HTML tags + // Define allowed HTML tags for markdown rendering + const allowedTags = new Set([ + 'p', 'br', 'strong', 'b', 'em', 'i', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'ul', 'ol', 'li', 'blockquote', 'code', 'pre', 'a', 'img', 'hr', + 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'del', 'ins' + ]); + + // Remove dangerous content first + let sanitizedHtml = html .replace(/]*>.*?<\/script>/gi, "") .replace(/]*>.*?<\/iframe>/gi, "") .replace(/]*>.*?<\/object>/gi, "") @@ -261,6 +269,23 @@ export function renderMarkdown( .replace(/on\w+="[^"]*"/gi, "") // Remove event handlers .replace(/javascript:/gi, "#"); + // Remove any HTML tags that are not in the allowed list + sanitizedHtml = sanitizedHtml.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)(?:\s[^>]*)?>/g, (match, tagName) => { + return allowedTags.has(tagName.toLowerCase()) ? match : ''; + }); + + // Remove all style attributes from allowed tags and ensure img tags have controlled styling + sanitizedHtml = sanitizedHtml.replace(/<([^>]+)>/g, (match, content) => { + // For img tags, ensure they have our controlled style + if (content.trim().startsWith('img')) { + // Remove any existing style and add our controlled one + const withoutStyle = content.replace(/\s+style="[^"]*"/gi, ''); + return `<${withoutStyle} style="max-height: 150px;">`; + } + // Remove style attributes from all other tags + return `<${content.replace(/\s+style="[^"]*"/gi, '')}>`; + }); + // Return a div with dangerouslySetInnerHTML return (
Date: Thu, 16 Oct 2025 16:48:41 +0100 Subject: [PATCH 3/4] lint --- src/lib/ircUtils.tsx | 47 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/lib/ircUtils.tsx b/src/lib/ircUtils.tsx index 4a71856a..d8eb49b7 100644 --- a/src/lib/ircUtils.tsx +++ b/src/lib/ircUtils.tsx @@ -252,9 +252,35 @@ export function renderMarkdown( // Additional security: only allow specific markdown-related HTML tags // Define allowed HTML tags for markdown rendering const allowedTags = new Set([ - 'p', 'br', 'strong', 'b', 'em', 'i', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', - 'ul', 'ol', 'li', 'blockquote', 'code', 'pre', 'a', 'img', 'hr', - 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'del', 'ins' + "p", + "br", + "strong", + "b", + "em", + "i", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "ul", + "ol", + "li", + "blockquote", + "code", + "pre", + "a", + "img", + "hr", + "table", + "thead", + "tbody", + "tr", + "th", + "td", + "del", + "ins", ]); // Remove dangerous content first @@ -270,20 +296,23 @@ export function renderMarkdown( .replace(/javascript:/gi, "#"); // Remove any HTML tags that are not in the allowed list - sanitizedHtml = sanitizedHtml.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)(?:\s[^>]*)?>/g, (match, tagName) => { - return allowedTags.has(tagName.toLowerCase()) ? match : ''; - }); + sanitizedHtml = sanitizedHtml.replace( + /<\/?([a-zA-Z][a-zA-Z0-9]*)(?:\s[^>]*)?>/g, + (match, tagName) => { + return allowedTags.has(tagName.toLowerCase()) ? match : ""; + }, + ); // Remove all style attributes from allowed tags and ensure img tags have controlled styling sanitizedHtml = sanitizedHtml.replace(/<([^>]+)>/g, (match, content) => { // For img tags, ensure they have our controlled style - if (content.trim().startsWith('img')) { + if (content.trim().startsWith("img")) { // Remove any existing style and add our controlled one - const withoutStyle = content.replace(/\s+style="[^"]*"/gi, ''); + const withoutStyle = content.replace(/\s+style="[^"]*"/gi, ""); return `<${withoutStyle} style="max-height: 150px;">`; } // Remove style attributes from all other tags - return `<${content.replace(/\s+style="[^"]*"/gi, '')}>`; + return `<${content.replace(/\s+style="[^"]*"/gi, "")}>`; }); // Return a div with dangerouslySetInnerHTML From 33cdf561c839c84c9931e9378ce9d66f58789a40 Mon Sep 17 00:00:00 2001 From: Valerie Liu Date: Thu, 16 Oct 2025 16:56:45 +0100 Subject: [PATCH 4/4] Strip all HTML tags from input before markdown processing - Prevent raw HTML injection by removing all HTML tags before parsing - Block dangerous HTML like
from being processed - Ensure only markdown-generated HTML can be rendered --- src/lib/ircUtils.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/ircUtils.tsx b/src/lib/ircUtils.tsx index d8eb49b7..a45fabec 100644 --- a/src/lib/ircUtils.tsx +++ b/src/lib/ircUtils.tsx @@ -240,6 +240,9 @@ export function renderMarkdown( return `${text}`; }; + // Strip all HTML tags from input before markdown processing + const textWithoutHtml = text.replace(/<[^>]*>/g, ""); + marked.setOptions({ breaks: true, gfm: true, @@ -247,7 +250,7 @@ export function renderMarkdown( }); // Parse markdown to HTML - const html = marked.parse(text) as string; + const html = marked.parse(textWithoutHtml) as string; // Additional security: only allow specific markdown-related HTML tags // Define allowed HTML tags for markdown rendering