Security

REALM treats some sources as code and everything else as data.

Source Treated as
Component definitions, inline or loaded with <import-element> Code, like a <script src>
Native on* handler attributes in definition markup Code, compiled with the component's script
Every other attribute in markup References only. No expression is ever evaluated
Value slots Text, unless the slot has html
HTML inserted later: html slots, render responses Data. Sanitised, and never scanned for handlers, references or bindings
Responses loaded with into Data. Shown as text by slots and bindings

Sanitising

<slot name="#x" html> and the render fetch attribute parse the HTML with DOMParser and remove:

The sanitiser is deliberately small. It blocks script execution, but it does not limit layout or styling attributes, and it does not stop a <form> in untrusted HTML from posting somewhere. For user-generated rich text, sanitise on the server with an allow-list as well.

html-unsafe skips sanitising. Only use it for HTML you produced yourself.

Text values are always inserted as text nodes, and attribute bindings use setAttribute, so state values cannot inject markup. A bound URL attribute such as _href="#link.url" is set as given. Validate URLs that come from users before putting them in state.

No eval

REALM never uses eval, new Function or blob: URLs. Component scripts and their handlers are assembled into a script element and inserted into the page. Handler attributes on plain pages for custom events are compiled the same way.

Content Security Policy

REALM works under a nonce-based policy. Give the page's REALM <script> tag a nonce. REALM copies the nonce from the first script[nonce] in the document onto every script it inserts:

<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-r4nd0m' 'strict-dynamic'; style-src 'self' 'unsafe-inline'">
<script type="module" nonce="r4nd0m" src="/realm/realm.js"></script>

Limits:

Imported components

<import-element from="https://…"> runs code from that origin in your page, like a <script src>. Only import from origins you trust, pin versions on CDNs, and restrict them with script-src and connect-src.

Checklist

Edit this page on GitHub · View as Markdown