Vitni loads WebAssembly components, grants them capabilities, and makes network requests on their behalf. That is a real attack surface, so vulnerability reports are welcome and will be handled seriously.
Do not open a public issue.
GitHub's private vulnerability reporting (Security → Report a vulnerability) is the preferred
route. Email magne.rasmussen@gmail.com with [vitni security] in the subject also works.
Useful in a report:
- what an attacker can do, and what they need to start (a crafted import file, a plugin bundle, a
workspace on disk, a
config.tomlvalue, network position); - the commit or release you tested, the platform, and whether it was a debug or release build;
- reproduction steps, ideally a minimal input file or bundle. Redact real genealogy data — synthetic names are fine and preferred.
Expectations. This is a single-maintainer project, not a company with a rota: acknowledgement within 7 days, an assessment within 14, and a fix schedule agreed with you from there. Fixes land in public commits with the vulnerability described in the commit message and release notes, and you get credit under whatever name you prefer, or none. There is no bug bounty. Please give the fix a chance to ship before disclosing publicly; if a report goes unanswered for 30 days, disclose.
Anything that breaks a boundary the program claims to hold:
- Plugin sandbox escape — a
wasm32-wasip2component reaching the filesystem, the network, the process, or host memory other than through thevitni:host-apiWIT world (ADR 0007, ADR 0011). - Capability bypass — an operation performed without the grant it is gated on. The grants are
query,commands,log,progress,import-source,export-sink,net,media-store,aiandpresent; deny-by-default is the invariant, and a plugin doing something itsplugin.tomlnever declared is a bug in this class. So is escaping thenetpolicy's host allow-list, or writing outside the media library throughmedia-store. - Signature and trust-tier bypass — making a bundle classify as
SanctionedorUserTrustedwithout a signature from a trusted key, or getting a tier to widen what a plugin may do (ADR 0014 §3: a tier says who signed a bundle, never what it may do). - Resource exhaustion that the fuel and memory limits are supposed to bound — a plugin that hangs or OOMs the host despite them.
- Malicious input — path traversal, decompression bombs, XXE-style entity abuse or memory exhaustion reachable from a GEDCOM, Gramps XML or Digitalarkivet file, or from a media file.
- Integrity of the record — anything that silently drops, rewrites or reorders committed events,
or that lets an operator's identity in an
EventContextbe forged. The event log is the evidence layer; a correction must be a new assertion, never an edit. - Credential leaks — an API key from
config.tomlor the environment ([map],[ai]) reaching a plugin, a log line, a crash report, or an export.
signing::DEV_PUBLIC_KEY/dev_signing_key()being in the source tree (crates/vitni-plugin-host/src/trust.rs). It is deliberate: debug and CI builds trust it so the first-party plugin fleet classifies as sanctioned during testing, and a release build never trusts it — the release key arrives at packaging time through the compile-timeVITNI_PROJECT_PUBLIC_KEY. A release binary that does trust the dev key would be a genuine finding.- A plugin abusing a capability you granted it. The grant is the security boundary; the program will not second-guess it.
- Anything requiring an attacker to already have write access to your workspace directory, your
~/.config/vitni/, or the binary itself. - Missing hardening with no demonstrated impact (a compiler flag, a header, a dependency version) — useful, but file it as a normal issue.
- Reports generated by a scanner with no analysis attached.
Pre-1.0 and pre-release: there is no supported-version matrix yet. Fixes go to main, and to the
newest release once releases exist. Older commits and tags get nothing backported.
Plugin bundles are authenticated with detached ed25519 signatures over a canonical digest of
plugin.toml + plugin.wasm. Verification fails closed: a bundle carrying a signature that matches no
trusted key is a hard error, while an unsigned bundle stays loadable but untrusted and is never
auto-granted anything. Trust roots are the sanctioned key compiled into the binary plus publisher keys
the user pinned. ADR 0014 is the full account.