> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lumen.bjanczak.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lumen Editor Security Model: XSS, RCE, and Upload Safety

> Lumen Editor provides built-in XSS protection, RCE prevention, SSRF mitigation, and file upload validation so your users are protected by default.

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:

<Accordion title="Allowed tags and attributes">
  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>`.
</Accordion>

<Accordion title="Event handler attributes">
  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.
</Accordion>

<Accordion title="Dangerous URL protocols">
  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.).
</Accordion>

<Accordion title="Style attribute filtering">
  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.
</Accordion>

## Safe output

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

<CardGroup cols={2}>
  <Card title="Always-sanitized getHTML()" icon="shield-check">
    `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.
  </Card>

  <Card title="No eval or dynamic scripts" icon="code">
    The editor itself never calls `eval()`, `new Function()`, or creates dynamic `<script>` elements internally. All DOM manipulation uses `textContent` and sanitized `innerHTML` assignments.
  </Card>

  <Card title="CSP-compatible" icon="lock">
    Because no inline scripts are injected at runtime, Lumen Editor works in environments with a strict Content Security Policy (`script-src` without `'unsafe-inline'`).
  </Card>

  <Card title="Error events for visibility" icon="bell">
    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))`.
  </Card>
</CardGroup>

## 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.

```js theme={null}
// 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:

<Steps>
  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="Size check">
    Files larger than `maxImageSize` (default **5 MB**) are rejected before any upload attempt is made.
  </Step>

  <Step title="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.
  </Step>
</Steps>

<Warning>
  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.
</Warning>

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.

## External links

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.

```html theme={null}
<!-- 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.
