Security
Alacris is small enough to audit in an afternoon — the entire runtime is about 1,500 lines with zero dependencies. This page states the security model precisely, so you know what is guaranteed and what you opt into.
Interpolated values are never HTML
Section titled “Interpolated values are never HTML”The only thing ever parsed as HTML is the static strings of a tagged
template — code you wrote, not data. Values in ${} travel a different path
entirely:
- Child positions are written with
textContent/createTextNode. A value of<img onerror=...>renders as those literal characters. - Attribute positions are written with
setAttribute. A value cannot terminate the attribute or open a new tag, because it is never parsed.
const evil = '<img src=x onerror="alert(1)">';html`<p>${evil}</p>` // renders the string, harmlesshtml`<p title=${evil}></p>` // an attribute value, harmlessSo there is no escaping to do, and no way to forget it. This holds for the initial render and for every reactive update after it.
The escape hatches, named
Section titled “The escape hatches, named”Three places intentionally let you hand the browser something live. Each one is syntactically explicit — you cannot wander into them:
.innerHTML=${value}— a property binding assigns the property you named. Binding.innerHTMLmeans you are asserting the value is safe HTML. Never point it at data you did not author; if you must render rich text, sanitize it first (for example with DOMPurify).- URL attributes —
href=${url}writes whatever string you pass, andjavascript:URLs execute on click. Validate the scheme of any user-supplied URL (http:/https:/mailto:) before binding it. cssinterpolation — interpolating into acsstemplate inlines text into a stylesheet. It exists so author sheets andvars()tokens compose. Runtime and user-influenced values belong in custom properties, which are inert values, not CSS text.
Content Security Policy
Section titled “Content Security Policy”The runtime contains no eval, no new Function, and no string-to-code path
of any kind, so a strict script-src policy works unmodified.
Under Trusted Types
(require-trusted-types-for 'script'), template parsing goes through a policy
named alacris that passes the static template strings through unchanged —
sound, because values never travel that path. Allow it alongside your own
policies:
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types alacrisA .innerHTML=${value} binding is deliberately not covered by the policy:
under Trusted Types the browser will reject a plain string there unless you
pass TrustedHTML from your own (sanitizing) policy — which is exactly the
enforcement you turned Trusted Types on for.
The store blocks prototype pollution
Section titled “The store blocks prototype pollution”A reactive store is exactly where applications merge parsed JSON, and
__proto__ is the one string key where a plain assignment mutates the
prototype chain instead of the object. The store’s proxy refuses to walk or
write it, and closes the constructor route to the same place:
state['__proto__']reads asundefined— the classic two-key gadgetstate[a][b] = vwith attacker-controlled keys has nothing to land on.- The inherited
constructoralso reads asundefined, closing the three-key variantstate[a][b][c] = vthat walksconstructor.prototype. An own key namedconstructor(data you stored) still reads back normally. - Assigning
__proto__through the store (including viaObject.assign(state, JSON.parse(input)), where JSON can carry an own__proto__key) is silently dropped, so the merge keeps working and the prototype chain does not move. Object.getPrototypeOf,instanceof, and normal inheritance are unaffected.
This is defense in depth, not permission to trust input: validate the shape of anything you merge into state.
Supply chain
Section titled “Supply chain”- Zero runtime dependencies. What you audit is what runs.
- No install scripts. The package has no
postinstallor lifecycle hooks. dist/is built in CI from the sources in the same package —src/ships alongside it, so you can diff what you serve against what you read.- CDN URLs pin an exact version
(
https://cdn.jsdelivr.net/npm/@alacris/core@0.11.3/dist/alacris.js). Use subresource-integrity-capable tooling if your pipeline supports it.
Reporting a vulnerability
Section titled “Reporting a vulnerability”Please report suspected vulnerabilities privately via GitHub security advisories rather than a public issue. See SECURITY.md for the full policy.