Skip to content

Trusted HTML and expression security

The simplest safe default is to display user content as text and keep Brio templates under your application’s control.

Directive expressions are ordinary strict-mode JavaScript, compiled and cached at runtime with new Function, without with.

Expressions are not a sandbox. Never render untrusted content as a Brio template or directive expression. Runtime compilation is incompatible with a strict CSP that disallows unsafe-eval.

b-text evaluates its source expression and writes the result as literal text. Tags and ${...} inside returned values are never interpreted. Authored HTML interpolation still evaluates once; its returned values also remain literal. b-html parses markup without activating Brio directives, interpolation, or contextual scripts. Both sources remain reactive:

<p b-text="$data.userText"></p>
<p>${$data.userText}</p>
<div b-html="$data.staticMarkup"></div>

Use b-text for untrusted/user-provided text. Inert HTML is not sanitized: HTML attributes and other browser behavior can still be dangerous.

ContentBrio behavior
b-text or the value returned by authored ${...} interpolationLiteral text; tags and ${...} in the returned value are not interpreted.
b-htmlParses HTML, but leaves Brio directives, interpolation, and contextual scripts inactive. Not sanitization.
b-html.hydrateActivates a Brio template only when explicitly marked with trustedHTML().

To activate a dynamic Brio template, explicitly use b-html.hydrate with a trustedHTML() value. Ordinary strings, null, and undefined are rejected in this mode. Use trustedHTML('') to clear an active template. Each replacement disposes previous effects, listeners, refs, and owned resources before hydrating the new content. A value without the trust marker is rejected before replacing existing content. Authored b-template and managed insertion are unchanged.

import { createApp, trustedHTML } from '@jnreis/briojs';
createApp({ state: () => ({ content: '<em>Trusted</em>' }) }).mount('#content');
<div id="content" b-html.hydrate="trustedHTML($data.content)"></div>

Only call trustedHTML() with templates you trust as application code. It is a trust assertion, not sanitization or a security boundary. Sanitizing ordinary HTML does not necessarily make it safe to execute as a Brio template.