diff --git a/app/javascript/dashboard/helper/emailQuoteExtractor.js b/app/javascript/dashboard/helper/emailQuoteExtractor.js index 775dc4db4..f29d48cca 100644 --- a/app/javascript/dashboard/helper/emailQuoteExtractor.js +++ b/app/javascript/dashboard/helper/emailQuoteExtractor.js @@ -1,3 +1,5 @@ +import DOMPurify from 'dompurify'; + // Quote detection strategies const QUOTE_INDICATORS = [ '.gmail_quote_container', @@ -29,7 +31,7 @@ export class EmailQuoteExtractor { static extractQuotes(htmlContent) { // Create a temporary DOM element to parse HTML const tempDiv = document.createElement('div'); - tempDiv.innerHTML = htmlContent; + tempDiv.innerHTML = DOMPurify.sanitize(htmlContent); // Remove elements matching class selectors QUOTE_INDICATORS.forEach(selector => { @@ -56,7 +58,7 @@ export class EmailQuoteExtractor { */ static hasQuotes(htmlContent) { const tempDiv = document.createElement('div'); - tempDiv.innerHTML = htmlContent; + tempDiv.innerHTML = DOMPurify.sanitize(htmlContent); // Check for class-based quotes // eslint-disable-next-line no-restricted-syntax diff --git a/app/javascript/dashboard/helper/specs/emailQuoteExtractor.spec.js b/app/javascript/dashboard/helper/specs/emailQuoteExtractor.spec.js index 7bd2aaa51..20b50581b 100644 --- a/app/javascript/dashboard/helper/specs/emailQuoteExtractor.spec.js +++ b/app/javascript/dashboard/helper/specs/emailQuoteExtractor.spec.js @@ -96,4 +96,58 @@ describe('EmailQuoteExtractor', () => { it('detects quotes for trailing blockquotes even when signatures follow text', () => { expect(EmailQuoteExtractor.hasQuotes(EMAIL_WITH_SIGNATURE)).toBe(true); }); + + describe('HTML sanitization', () => { + it('removes onerror handlers from img tags in extractQuotes', () => { + const maliciousHtml = '
Hello
Hello
'); + }); + + it('removes onerror handlers from img tags in hasQuotes', () => { + const maliciousHtml = 'Hello
Content
More
'; + const cleanedHtml = EmailQuoteExtractor.extractQuotes(maliciousHtml); + + expect(cleanedHtml).not.toContain('