2.5 KiB
2.5 KiB
01. Fix stored XSS via unsanitized innerHTML in blog rendering
meta: id: security-fixes-01 feature: security-fixes priority: P0 depends_on: [] tags: [implementation, tests-required, high-severity]
objective:
- Eliminate stored XSS in blog post rendering by replacing raw innerHTML with a sanitization pipeline
deliverables:
- Replace
contentToHtml()inweb/src/routes/blog/[slug].tsxwith a safe HTML rendering approach - Add DOMPurify (or equivalent) as a dependency to sanitize HTML before innerHTML binding
- Unit tests for the sanitization pipeline covering script injection, event handler injection, and data URI vectors
steps:
- Install
dompurifyandisomorphic-dompurify(for SSR compatibility) in the web app - Examine
contentToHtml()atweb/src/routes/blog/[slug].tsx:14-46and the innerHTML binding at line 121 - Create a
sanitizeHtml(content: string): stringutility that runs DOMPurify on the rendered HTML - Replace the innerHTML binding with
innerHTML={sanitizeHtml(contentToHtml(post.content))} - Consider replacing the custom markdown-to-HTML parser with a library (e.g.,
marked+ DOMPurify) if the custom implementation is fragile - Add unit tests covering XSS vectors:
<script>,onerror=,javascript:,data:text/html
tests:
- Unit:
sanitizeHtml()strips<script>tags, event handlers (onclick,onerror, etc.),javascript:URIs, anddata:text/htmlURIs - Unit:
sanitizeHtml()preserves legitimate HTML (headings, paragraphs, links, lists, code blocks) - Integration: Blog post with embedded script renders without executing JavaScript (verify via headless test or DOM inspection)
acceptance_criteria:
- innerHTML is never bound with unsanitized content
- DOMPurify (or equivalent) is called on all HTML before it reaches the DOM
- Unit tests pass for all XSS vector categories (script, event handlers, data URIs, javascript: URIs)
- Legitimate blog formatting (headings, links, bold, italic, code) still renders correctly
validation:
cd web && bun test— all tests pass- Manually create a blog post with
<script>alert(1)</script>content and verify it does not execute - Review the rendered HTML output to confirm sanitization is applied
notes:
- Finding p8-001 is the only HIGH severity finding — prioritize this first
isomorphic-dompurifyis needed because DOMPurify requires a DOM environment (not available in Node SSR)- If SolidStart supports client-only rendering for this route, standard DOMPurify suffices