Sanitization & Security

Rich text editors are a primary vector for XSS attacks. Learn how to secure your editor against malicious content from paste operations and database injection.

Overview

Because contenteditable editors work directly with HTML, they are inherently susceptible to Cross-Site Scripting (XSS). If an attacker can inject a script tag or an event handler (like onload or onerror) into your document, they can execute arbitrary code in your users' browsers.

XSS Risks

Common attack vectors in editors include:

  • Paste: User pastes HTML containing <img src=x onerror=alert(1)>.
  • Data Loading: Loading compromised JSON/HTML from the server.
  • Drag & Drop: Dropping malicious HTML fragments.

Sanitization Strategy

Never trust HTML. Always sanitize it before inserting it into the DOM. We recommended using DOMPurify.

import DOMPurify from 'dompurify';

// Configure allowed tags and attributes
const config = {
  ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a', 'ul', 'ol', 'li'],
  ALLOWED_ATTR: ['href', 'target', 'class'],
  FORBID_TAGS: ['script', 'style', 'iframe', 'object'],
  FORBID_ATTR: ['onclick', 'onerror', 'onmouseover']
};

export function sanitize(html: string) {
  return DOMPurify.sanitize(html, config);
}

Safe Paste Handling

When extracting content from the clipboard, use DOMParser to parse it into an inert document, then sanitize or transform it into your model immediately.

Warning: innerHTML

Never assign pasted text directly to innerHTML without sanitization. Even assigning it to a detached element can trigger network requests (e.g., <img src="...">).

Trusted Types

Trusted Types is a browser security feature that prevents DOM XSS by enforcing that only policy-verified strings can be assigned to dangerous sinks (like innerHTML).

// 1. Create a policy
const escapePolicy = trustedTypes.createPolicy('my-editor-policy', {
  createHTML: (string) => DOMPurify.sanitize(string)
});

// 2. Use the policy
const safeHTML = escapePolicy.createHTML('<p>Potentially unsafe</p>');
element.innerHTML = safeHTML;