Skip to content

Security

Strict CSP, Trusted Types and what to do on the server.

On this page

The editor works under a strict Content Security Policy with Trusted Types. This site itself runs under that policy.

Layers of defence

Security layers
LayerWhat it does
InputEvery input path (initial content, setContent, paste, drop, source view) passes through DOMPurify. Script-capable elements are removed before parsing.
ModelOnly schema-known content survives, unless HtmlSupport is added, and even then its blocklist applies.
OutputgetHTML() is produced by a serializer that does not use the DOM. It validates tag and attribute names, escapes every value and checks every URL again.
URLsAllowed by default: http, https, mailto and tel, plus relative URLs. data: images are off unless urlPolicy.allowDataImages is set.
CSPWorks under script-src 'self'; style-src 'self'; require-trusted-types-for 'script'. The live view never writes inline style strings.
Trusted TypesAdds one policy named open-wysiwyg-editor to your trusted-types directive, or pass your own with setTrustedTypesPolicy().

A recommended policy

Add the editor's policy name to trusted-types. Paste handling also uses ProseMirror's ProseMirrorClipboard policy, so list that one too.

Terminal
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self';
  img-src 'self' https: data:; require-trusted-types-for 'script';
  trusted-types open-wysiwyg-editor ProseMirrorClipboard

Trusted Types

With require-trusted-types-for 'script', every HTML sink needs a trusted value. The editor creates one policy and uses it everywhere.

The browser is not a security boundary

Never trust HTML that comes from the client. The editor cleans what it loads and produces, but anyone can post any string to your API. Sanitize again on the server, with a library you trust, before you store or render it for other users.
TypeScript
import sanitizeHtml from "sanitize-html"; // or isomorphic-dompurify

export async function savePost(formData: FormData) {
  const body = sanitizeHtml(String(formData.get("body") ?? ""));
  // store `body`
}

For initial content from users, use the value attribute or a <template> child on <owe-editor>, never raw children. Neither can run anything before the editor sanitizes it.

Found a vulnerability? Please report it privately, see the security policy.

Edit this page on GitHub