security sweep
This commit is contained in:
45
tasks/security-fixes/01-fix-stored-xss-blog-rendering.md
Normal file
45
tasks/security-fixes/01-fix-stored-xss-blog-rendering.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# 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()` in `web/src/routes/blog/[slug].tsx` with 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:
|
||||
1. Install `dompurify` and `isomorphic-dompurify` (for SSR compatibility) in the web app
|
||||
2. Examine `contentToHtml()` at `web/src/routes/blog/[slug].tsx:14-46` and the innerHTML binding at line 121
|
||||
3. Create a `sanitizeHtml(content: string): string` utility that runs DOMPurify on the rendered HTML
|
||||
4. Replace the innerHTML binding with `innerHTML={sanitizeHtml(contentToHtml(post.content))}`
|
||||
5. Consider replacing the custom markdown-to-HTML parser with a library (e.g., `marked` + DOMPurify) if the custom implementation is fragile
|
||||
6. 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, and `data:text/html` URIs
|
||||
- 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-dompurify` is needed because DOMPurify requires a DOM environment (not available in Node SSR)
|
||||
- If SolidStart supports client-only rendering for this route, standard DOMPurify suffices
|
||||
Reference in New Issue
Block a user