From 156c5bae35159ead3616c983c99d4bd17f61abe5 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Sun, 9 Aug 2026 16:36:01 -0700 Subject: [PATCH] fix(site-builder): widen Custom HTML block sanitiser allow-list A customer's broad HTML fixture showed 38% of it silently deleted by the shipped DOMPurify config: colspan/rowspan/scope,
, /,
/, inline ,
    were all stripped. The site owner's call: be generous, this block is an explicit escape hatch, allow forms too. Widens PURIFY_CONFIG in HtmlBlock.tsx (45->119 tags, 16->108 attrs; form/input/button/select/textarea removed from FORBID_TAGS) while keeping the four non-negotiables intact: no '); + expect(out).not.toContain(' { + const out = purifyHtml(''); + expect(out).not.toMatch(/onfocus/i); + const out2 = purifyHtml(''); + expect(out2).not.toMatch(/onchange/i); + }); + + test('javascript: blocked in
    ', () => { + const out = purifyHtml('
    '); + expect(out).not.toContain('javascript:'); + }); + + test('formaction is not in the allow-list at all -- dropped regardless of value', () => { + const out = purifyHtml(''); + expect(out).not.toContain('formaction'); + expect(out).not.toContain('javascript:'); + }); + + test('javascript: blocked on svg (xlink:href is not allow-listed at all)', () => { + const out = purifyHtml('click'); + expect(out).not.toContain('javascript:'); + expect(out).not.toContain('xlink:href'); + }); + + test('javascript: blocked in newly-allowed media URL attributes (poster, source src)', () => { + const out = purifyHtml(''); + expect(out).not.toContain('javascript:'); + }); + + test('javascript: still blocked in plain href alongside the widened surface', () => { + const out = purifyHtml('x'); + expect(out).not.toContain('javascript:'); + }); + + test('iframe still gets the forced restrictive sandbox + referrerpolicy alongside the widened surface', () => { + const out = purifyHtml('
    '); + expect(out).toMatch(/]*\bsandbox="[^"]+"/); + const sandbox = out.match(/sandbox="([^"]*)"/)![1]; + expect(sandbox).not.toMatch(/allow-top-navigation/); + expect(out).toContain('referrerpolicy="no-referrer"'); + }); + + test('on* on an iframe is still stripped even though iframe now sits among many more allowed siblings', () => { + const out = purifyHtml(''); + expect(out).not.toMatch(/onload/i); + }); + + test('style tag stays blocked even nested inside the newly-allowed inline svg', () => { + const out = purifyHtml(''); + expect(out).not.toMatch(/