Skip to Content
SumX EditorSanitization & XSS

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 / sanitizeEditorHtml before persistence or display
  • RichTextContent for read views (sanitizes internally)

sanitizeRichHtml

import { sanitizeRichHtml, RICH_HTML_SANITIZE_CONFIG, } from '@sumx/sumx-editor/sanitize-rich-html';
ExportDescription
sanitizeRichHtml(html)Returns safe HTML string; empty input → ''
RICH_HTML_SANITIZE_CONFIGDOMPurify Config — extend only with security review

Implementation: isomorphic-dompurify — runs on server and client (SSR-safe previews).

Profile highlights

SettingBehavior
USE_PROFILES.htmlStandard safe HTML subset
ALLOWED_URI_REGEXPhttps?, mailto, tel, relative-safe patterns
ADD_ATTRdata-sumx-variable for merge-field chips
ALLOW_DATA_ATTRfalse
FORBID_TAGSscript, style, iframe, form, input, …
FORBID_ATTRformaction

Blocked content examples

InputResult
<script>alert(1)</script>Stripped
<img src=x onerror=alert(1)>Unsafe attrs removed
javascript:alert(1) in hrefBlocked 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 onChange from 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" />
PropDescription
htmlRaw stored HTML (nullable)
emptyPlaceholderShown when sanitized output is empty
classNameWrapper 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.