Sanitization & XSS
Rich HTML from WYSIWYG editors is untrusted until sanitized. @sumx/sumx-editor uses one DOMPurify profile everywhere: editing, storage round-trips, and read-only display.
Rule
Never render editor HTML with raw dangerouslySetInnerHTML. Always use:
sanitizeRichHtml/sanitizeEditorHtmlbefore persistence or displayRichTextContentfor read views (sanitizes internally)
sanitizeRichHtml
import {
sanitizeRichHtml,
RICH_HTML_SANITIZE_CONFIG,
} from '@sumx/sumx-editor/sanitize-rich-html';| Export | Description |
|---|---|
sanitizeRichHtml(html) | Returns safe HTML string; empty input → '' |
RICH_HTML_SANITIZE_CONFIG | DOMPurify Config — extend only with security review |
Implementation: isomorphic-dompurify — runs on server and client (SSR-safe previews).
Profile highlights
| Setting | Behavior |
|---|---|
USE_PROFILES.html | Standard safe HTML subset |
ALLOWED_URI_REGEXP | https?, mailto, tel, relative-safe patterns |
ADD_ATTR | data-sumx-variable for merge-field chips |
ALLOW_DATA_ATTR | false |
FORBID_TAGS | script, style, iframe, form, input, … |
FORBID_ATTR | formaction |
Blocked content examples
| Input | Result |
|---|---|
<script>alert(1)</script> | Stripped |
<img src=x onerror=alert(1)> | Unsafe attrs removed |
javascript:alert(1) in href | Blocked by URI rules |
| Allowed merge field | <span class="sumx-editor-variable" data-sumx-variable="…"> preserved |
sanitizeEditorHtml
Alias used inside the editor module — identical to sanitizeRichHtml:
import { sanitizeEditorHtml } from '@sumx/sumx-editor';sumx-editor-core sanitizes on:
- Every
onChangefrom SunEditor setContents/ value sync- Paste handling paths that set HTML
RichTextContent
import RichTextContent from '@sumx/sumx-editor/rich-text-content';
<RichTextContent
html={dto.bodyHtml}
emptyPlaceholder="No content"
className="max-w-3xl"
/>| Prop | Description |
|---|---|
html | Raw stored HTML (nullable) |
emptyPlaceholder | Shown when sanitized output is empty |
className | Wrapper classes (prose, spacing) |
Uses Typography (prose) with font-size reverts so display matches editor output rather than forcing prose-sm.
Portal shim
// src/shared/lib/sanitize-rich-html.ts
export { sanitizeRichHtml, RICH_HTML_SANITIZE_CONFIG } from '@sumx/sumx-editor/sanitize-rich-html';Validation vs sanitization
- Sanitization — required at render and on editor output; defense in depth.
- Zod / API validation — still validate shape, max length, required fields in
schemas/and BFF routes. Do not treat sanitization as a substitute for server-side validation on APIs you control.
Authorization
Sanitization does not replace permission checks. Hiding an edit button client-side is UX only; enforce on the server.