Use GitHub's private vulnerability reporting on this repository: Report a vulnerability. Do not open a public issue. Include the version and a minimal page or script that reproduces it.
In scope: code in this repository that turns data into DOM, for example a binder or the {{key}} bindings parser writing a value as HTML where the docs say it writes text, or prototype pollution through set, calc, setData or delegated event paths.
Out of scope: the html binder and itemRenderer/renderer templates, which write what they are given as HTML by design — escaping untrusted data before it reaches them is the application's job.
Every version is published from GitHub Actions through npm trusted publishing, with an npm provenance attestation signed through Sigstore. In a project that installs it, npm audit signatures checks the registry signature and the attestation; npm fetches the public keys itself (https://registry.npmjs.org/-/npm/v1/keys). Each GitHub Release carries the same attestation (v<version>.intoto.jsonl).
- The maintainer acknowledges the report within 14 days.
- The maintainer reproduces it and agrees on the impact with the reporter in the private advisory.
- The fix gets a regression test that fails on the code before it, and ships as a patch release of the latest version, within 60 days for a confirmed vulnerability.
- The advisory is published with the release, with a CVE when one applies, and the CHANGELOG entry links it.
Reporters are credited in the advisory and the CHANGELOG entry, unless they ask not to be.
- A value bound with a text binder (
text, the default binders for inputs and outputs,{{key}}in markup) is written as text, never parsed as HTML. - A key named
__proto__,constructorortoString(set,setData) is stored as an own key, and a path through__proto__(calc,bindNode,on('a.b@…')) never reachesObject.prototype. - The library runs no code from strings (no
eval, nonew Function), so it works under a Content Security Policy withoutunsafe-eval. - No runtime dependencies.
What it does not do: the html binder and the itemRenderer/renderer templates write HTML by design, and an attribute binder writes the value as given (a javascript: URL in an href included). Escaping or checking untrusted data before it reaches them is the application's job.
- Threat model. The attacker controls data the application puts into Matreshka objects: field values typed into a page, JSON from a server, keys of that JSON. The attacker does not control the application's code, its templates or its binder choices.
- Trust boundary. Values and keys are untrusted; code, selectors, templates and binders are trusted. The library treats every value as data and every key as a plain name.
- Why the requirements hold. Text binders write through
textContent,valueand similar DOM properties, neverinnerHTML. Per-object state lives in aWeakMap, in tables made withObject.create(null), and a__proto__step in a key or a path reads and writes only an own property, so no key reachesObject.prototype. There is no code path that turns a string into code. Secure design principles: least privilege (the library only touches the nodes it is given), fail-safe defaults (text, not HTML, unless thehtmlbinder is chosen), economy of mechanism (no dependencies, one small DOM layer). - Weaknesses countered. CWE-79 (XSS) through the text-only defaults; CWE-1321 (prototype pollution) through null-prototype tables and own-property
__proto__steps; CWE-1333 (ReDoS) through regexes CodeQL checks for polynomial backtracking; CWE-94 (code injection) through no string evaluation; supply-chain attacks through zero dependencies, actions pinned by SHA, trusted publishing and provenance. - Evidence. Tests for each of these, in
test/spec/regressions/(codeql_2026_10_17_spec.jsholds the CodeQL findings) and the property tests intest/spec/properties_spec.js; 100% coverage; CodeQL on every push and pull request, with no open alerts; OpenSSF Scorecard onmain.
Fixes ship in the latest version — no backports. The software is provided as is, without warranty of any kind, per the MIT license.