security: sanitize email HTML with DOMPurify before iframe rendering#274
Conversation
|
Self-review of DOMPurify sanitization PR. Code review:
Security analysis:
Potential consideration: CI passing. Ready to merge. |
Self-ReviewDiscussion thread status:
Checked:
E2E Testing:
Issues found:
Confidence: High |
b36de33 to
2514840
Compare
hoiekim
left a comment
There was a problem hiding this comment.
Is there any way to do this without an external lib?
Defense-in-depth for email viewer: sanitize HTML content with DOMPurify before it's rendered in the sandboxed iframe. The iframe already has sandbox="allow-same-origin allow-popups" which blocks script execution. DOMPurify adds a second layer by stripping script tags, event handlers, and other XSS vectors from the HTML body before it reaches the iframe srcdoc. Config: - ADD_ATTR: ["target", "rel"] — allow link target/rel for email links - FORCE_BODY: true — keeps style elements and full email structure - ALLOW_DATA_ATTR: false — strip data-* attributes Closes hoiekim#124
Use DOMParser to strip dangerous elements (script, iframe, object, etc.) and event handler/javascript: attributes before injecting email HTML into the viewer iframe. No external dependency needed — the sandbox iframe already blocks script execution; this is defense-in-depth using the browser's own HTML parser. Removes dompurify and @types/dompurify from package.json.
2514840 to
6d0acfc
Compare
moltboie
left a comment
There was a problem hiding this comment.
Good point. Replaced DOMPurify with a native DOMParser-based sanitizer — no external dependency needed.
What it does:
- Parses the HTML with
DOMParser(same engine the browser uses) - Removes dangerous elements:
script,iframe,object,embed,applet,base - Strips
on*event handler attributes andjavascript:/vbscript:/data:URIs fromhref/src/action - Returns the serialized clean HTML
Removed dompurify and @types/dompurify from package.json — the new implementation is ~25 lines of native browser API.
The iframe sandbox (allow-same-origin allow-popups without allow-scripts) still provides the primary defense; this is defense-in-depth without adding a dependency.
Summary
Defense-in-depth for the email viewer: sanitize HTML content with DOMPurify before it's rendered in the sandboxed iframe.
Closes #124
Background
Follow-up from #121 (iframe XSS fix). The iframe has
sandbox="allow-same-origin allow-popups"which blocks script execution. This PR adds DOMPurify as a second layer.Changes
src/client/lib/html.tsimport DOMPurify from "dompurify"processHtmlForViewer: sanitizehtmlinput with DOMPurify before injecting into iframe srcDocDOMPurify config:
What DOMPurify strips
<script>tagsonclick,onload, etc.)javascript:URIsWhat it preserves
<style>blocks<a href>) with target/rel attributesTesting
bun run dev)Self-Review
Discussion thread status:
Checked:
bun run buildpasses ✅bun run tsc --noEmitclean ✅processHtmlForViewerstill exported fromsrc/client/lib/index.ts✅dompurifyis client-only; all usages ofprocessHtmlForViewerare in client components ✅Not checked: