Untrusted content
The editor is built to render documents written by someone else, such as a teammate or an AI agent. Rendering a document never runs its script:
- Raw HTML is shown as source, never rendered.
- Math (Temml,
trust: false) and the editor's icons reach the DOM only through one sanitiser with an allowlist of elements and attributes. Unknown elements make the formula fall back to its source. Unknown attributes are dropped. - Mermaid runs with
securityLevel: "strict"and no HTML labels. Its SVG goes through the same allowlist. - Links are classified the way a browser reads them, after decoding entities and removing
control characters.
javascript:,vbscript:,livescript:anddata:links are never passed toopenLinkoropenExternal, however they are obfuscated. YourrefusedLinkis told instead. - Images: without a
resolveImage, only absolutehttps:images load. With one, script-capable URLs are still dropped.
What stays your job
Section titled “What stays your job”- Network policy. An
https:image in a document is loaded by the browser, which tells its server the page was opened. If that matters, returnnullfromresolveImagefor hosts you do not trust, or proxy images. - Opening links.
openExternalandopenLinkreceive URLs and paths the editor already classified as safe to follow; your policy still decides whether and how to open them. - Content Security Policy. CodeMirror injects
<style>elements, so a strictstyle-srcneeds a nonce through CodeMirror'sEditorView.cspNonce, passed withextensions:
import { EditorView } from "@codemirror/view";import { createEditorState } from "@openmarkdown-dev/editor";
const state = createEditorState({ doc, extensions: EditorView.cspNonce.of(nonce) });What a strict policy (script-src 'self'; style-src 'self' 'nonce-…', no 'unsafe-inline')
needs, exactly:
- The editor and math: only that nonce. The editor writes no
styleattribute; a formula's styles are applied throughelement.style, which the policy allows. - Diagrams: more. Mermaid draws each diagram once in the page to measure it, with
styleattributes and<style>elements that carry no nonce. Withoutstyle-src-attr 'unsafe-inline'andstyle-src-elem 'self' 'unsafe-inline'the browser blocks them and reports violations. Either add those two directives, or passdiagrams: falsetocreateEditorState(or import@openmarkdown-dev/editor/no-diagrams, which leaves Mermaid out of the build):mermaidblocks then stay code and Mermaid is never loaded. Self-hosting gives both policies, tested in a browser.
Known advisories
Section titled “Known advisories”npm audit reports one advisory in a fresh install; npm counts it as 3 low severity vulnerabilities, one for each package on the path (katex, mermaid and this package). We
assessed it, and it does not apply to the editor:
- GHSA-238p-pmpm-9mq7 (low;
katex, installed throughmermaid11.17.2): "KaTeX: Existing prototype pollution can bypass trust restrictions". Exploiting it needs a prototype pollution already present in the page and KaTeX output inserted without sanitising. The editor renders math with Temml, not KaTeX. Mermaid runs withhtmlLabels: false, so its labels are plain SVG text. Every piece of markup the editor inserts goes through its one sanitiser, which refuses anything outside its allow-list. The fix exists only in Mermaid 12, which adds a dependency under a license this package cannot take (EPL-2.0 OR GPL-3.0). With theno-diagramsentry, neither Mermaid nor KaTeX reaches your bundle. Next review: 2027-02-04.
The release check fails on any advisory that is not assessed here.
Reporting a vulnerability
Section titled “Reporting a vulnerability”Report vulnerabilities privately through the repository's GitHub security advisories, not in a public issue.