# Security Zoijs is **secure by default**. The safe path is the only path you'll normally use — you have to go out of your way to do something dangerous, and several dangerous things are simply blocked. ## Threat model Untrusted data (user input, API responses, URL params, stored content) flows into your templates. The goal: that data can **never** become executable script, markup, an event handler, or a dangerous URL. The core guarantee: **dynamic values fill text and attribute *slots* only — they can never change a template's structure.** The template scanner keeps your static HTML and your `${}` values in separate channels and refuses to put a value where a tag name, attribute name, or raw-HTML sink would go. ## Safe rendering rules | What you write | What happens | Safe? | |---|---|---| | `${() => value}` in text | rendered as an **inert Text node** (escaped) | ✅ always | | `attr=${() => value}` | set via `setAttribute` (or property for `value`/`checked`) | ✅ | | URL attrs (`href`, `src`, `action`, `formaction`, `poster`, `ping`, `xlink:href`) | **scheme-checked** | ✅ unsafe schemes blocked | | `onclick=${fn}` | `addEventListener` with a **function reference** | ✅ strings ignored | ### Text is always escaped ```js html`

${() => userInput}

`; // userInput = "" → shown as literal text. No element, no execution. ``` ### URLs are scheme-validated Allowed: `http`, `https`, `mailto`, `tel`, relative URLs, and raster `data:image/*` (png/jpeg/gif/webp/avif/bmp/ico). Blocked: `javascript:`, `vbscript:`, `data:text/html`, `data:image/svg+xml`, and any unknown scheme. The check also strips control characters first, so tricks like `java\tscript:` don't slip through. ```js html` url}>link`; // url = "javascript:alert(1)" → href is not set. ``` ### Event handlers are functions, never strings ```js html``; // ✅ function reference html``; // ⚠️ ignored — a string is never wired up or eval'd ``` ## Unsafe patterns to avoid These either **throw a clear error** or are **blocked**: | Pattern | Result | Do this instead | |---|---|---| | `<${tag}>` (dynamic tag) | throws | use a conditional returning different templates | | `` (dynamic/spread attribute name) | throws | name attributes statically: `disabled=${cond}` | | `