Skip to main content
Security is a first-class concern in Lumen Editor. Because a rich text editor is a direct pipeline from untrusted user input to rendered HTML, every layer of the editor — input, paste handling, image upload, and output — applies defensive controls. This page explains what those controls are, what they protect against, and what responsibilities remain on your side.

XSS protection

All HTML that enters the editor passes through an allowlist-based sanitizer before it touches the DOM. The sanitizer enforces rules at every level:
Only a curated set of semantic HTML tags and safe attributes are permitted. Everything else is stripped. This means elements designed to execute code or load external resources are removed entirely — including <script>, <iframe>, <object>, <embed>, <form>, <input>, <button>, <select>, and <textarea>.
Every attribute whose name begins with on (such as onclick, onmouseover, onerror) is removed unconditionally, regardless of its value. There is no allowlist exception for event handlers.
The href and src attributes on allowed elements are validated against a protocol allowlist. The following schemes are rejected: javascript:, vbscript:, and data: URIs except for explicitly whitelisted image MIME types (data:image/png;base64, data:image/jpeg;base64, etc.).
Inline style attributes are permitted only when every CSS property they contain is on the allowlist. Functions that can execute code or load remote resources — url(), expression(), and @import — are blocked even within otherwise-allowed properties.

Safe output

The editor is designed so that clean output requires no extra effort from you.

Always-sanitized getHTML()

editor.getHTML() returns HTML that has already passed through the sanitizer. You do not need to sanitize the return value a second time before persisting or rendering it.

No eval or dynamic scripts

The editor itself never calls eval(), new Function(), or creates dynamic <script> elements internally. All DOM manipulation uses textContent and sanitized innerHTML assignments.

CSP-compatible

Because no inline scripts are injected at runtime, Lumen Editor works in environments with a strict Content Security Policy (script-src without 'unsafe-inline').

Error events for visibility

When the sanitizer discards content, it emits an error event so you can log the occurrence without exposing detail to the end user: editor.on('error', (e) => console.warn(e.code)).

Paste protection

When a user pastes content from an external source, the editor intercepts the clipboard event before the browser’s default paste handler runs. The pasted HTML is fed through the same allowlist sanitizer used for all other input. If parsing the clipboard payload fails for any reason, the editor falls back to inserting the data as plain text, ensuring that a malformed paste can never inject raw markup.
// No action required — paste sanitization is automatic.
// You can observe the result via the change event:
editor.on('change', (html) => {
  console.log('Content after paste (sanitized):', html);
});

Image upload security

When a user inserts an image, Lumen Editor runs several client-side checks before invoking your uploadImage callback:
1

MIME type check

The file’s declared MIME type is validated against the allowedImageTypes list. Files reporting a type outside this list are rejected immediately.
2

Magic byte verification

The first bytes of the file buffer are inspected against known file signatures for PNG, JPEG, GIF, and WebP. A file whose bytes do not match its declared MIME type is rejected, preventing extension-spoofing attacks.
3

Size check

Files larger than maxImageSize (default 5 MB) are rejected before any upload attempt is made.
4

URL validation

After upload, the URL returned by your callback must use http: or https:. Client-side data:image/...;base64 URIs from the allowlist are also accepted. No other schemes are inserted into the document.
Client-side checks are a first line of defence, not a substitute for server-side validation. Your uploadImage endpoint must independently verify the file’s MIME type, size, and content before storing it. Never trust the MIME type reported by the browser alone.
The editor also does not fetch remote URLs on behalf of the user. Image URLs are stored as-is in the document; the editor never proxies or pre-fetches them, eliminating server-side request forgery (SSRF) risk from the editor itself. Any <a> element in the editor’s output — whether typed by the user or present in pasted content — automatically receives rel="noopener noreferrer". This prevents a linked page from accessing window.opener and protects against tab-napping attacks without any configuration on your part.
<!-- Editor output — rel is added automatically -->
<a href="https://example.com" rel="noopener noreferrer">Visit example</a>
For further hardening options — such as customizing the sanitizer allowlist or restricting allowed URL protocols — see the Sanitizer Configuration reference page.