# Security

Source: https://signy.dev/documentation/1/application/security/

What Signy does with untrusted data, and what is left to you.

## Text is text

A value in an `html` template is set as text, never parsed as markup. A comment that contains `<img onerror=...>` shows those characters and runs nothing.

```js
html`<p>${comment.body}</p>`;            // safe, whatever the body holds
html`<p title=${comment.author}>...</p>`;  // safe, set as an attribute value
```

## Attributes that could run code

Bindings, spreads, the `DOM` helpers and router links refuse three kinds of value. The attribute is left out, and dev builds log `view:unsafe-attribute` when [warnings are on](https://signy.dev/documentation/1/application/dev-tools/index.html.md#log-level).

- An `on` attribute given a string, such as `onclick=${'alert(1)'}`. Handlers must be functions.
- `srcdoc`, which holds a whole document.
- A `javascript:` or `vbscript:` URL, or a `data:` URL that is not an image, in `href`, `src`, `action`, `formaction`, `poster`, `data` or `xlink:href`. Spaces and control characters hidden in the scheme do not get past the check.

Every other URL is allowed, including links to other sites. Check the host yourself when a link must stay on your site.

## Raw HTML

Templates have no way to insert an HTML string. When you need one, such as rendered Markdown, you write it yourself through a ref, and that is where untrusted data must be cleaned.

```js
html`<div ref=${(el) => (el.innerHTML = sanitizeHtml(post.body, ['p', 'b', 'i', 'ul', 'li']))}></div>`;
```

- `escapeHtml(value)` escapes `&`, `<`, `>` and both quotes.
- `sanitizeHtml(html, tags)` keeps only the listed tags, drops every attribute, and drops `script` and `style` with their contents. Without a list it escapes everything.
- `stripHtml(html)` returns the visible text.

`sanitizeHtml()` removes all attributes, so links lose their `href`. For rich text with links and images, use a dedicated sanitizer such as DOMPurify. `DOM.createTemplate(html)` parses an HTML string too: pass it your own markup only.

## Store and query strings

- `store.merge()` and `update()` skip a `__proto__` key in the data, so merging parsed JSON cannot change `Object.prototype`.
- A `set()` path through `__proto__`, `constructor` or `prototype`, and an assignment to `state.__proto__`, throw `reactivity:store-unsafe-key`.
- The router parses `?__proto__=x` or `?toString=1` into plain keys of the query object, without touching prototypes.

## Your part

- Never pass user data to `innerHTML`, `outerHTML`, `insertAdjacentHTML()` or `DOM.createTemplate()` without a sanitizer.
- Check URLs from users before you put them in `href`, beyond the scheme check above.
- Use a Content Security Policy. Signy and the `html` template never call `eval()` or `new Function()`, so `'unsafe-eval'` is not needed.
