8416c5f3c3c7973b8cfc0e6e1dfc94b3a0650790
Defense-in-depth XSS guard at the client-side preview boundary. `renderEmailBody()` already escapes-then-allowlists on the server, but mounting that output via dangerouslySetInnerHTML still exposes a single point of failure: a server-side regression in the sanitizer would silently produce a client-side XSS via the preview surface. DOMPurify sanitizes one more time before injection, with the exact allow-list `renderEmailBody` produces: <p>, <br>, <strong>, <em>, <code>, <a> (with href/target/rel, https/mailto only). Anything broader gets stripped at the DOM-injection boundary. Wrapped in useMemo so the sanitize only runs when the preview HTML changes — negligible perf, no per-render cost. The hand-rolled markdown-email.ts pipeline stays as-is: its escape-first-then-rule-replace architecture is correct and the "don't add DOMPurify as a dep at the conversion layer" reasoning in its header comment still holds. We add DOMPurify at the *consumer* boundary (preview rendering) where the threat model is "what if the server slips and emits unsafe HTML." Verified: tsc clean, vitest 1293/1293 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Description
No description provided
Languages
TypeScript
98.7%
HTML
1%
CSS
0.1%
Shell
0.1%