Verify and surface build provenance for community plugins (trust badges now, provenance-drift protection on updates later)

Apologies ahead of time, this is a long one.

Use case or problem

Obsidian already treats community plugins as trusted code, and I know the team has been deliberately rolling out supply-chain protections. The gap I keep hitting is the silent update: when a new version of a plugin I already use lands, I get no signal about where that build came from or whether it matches what I installed before. Right now that trust rests on the author’s account not being compromised, and account compromise is the failure mode showing up most often across ecosystems.

Today Obsidian stores no supply-chain validation data at all. What exists locally is:

  • .obsidian/community-plugins.json: an array of enabled community plugin IDs
  • .obsidian/plugins/<plugin-id>/manifest.json: local metadata (id, name, installed version, minAppVersion, author, description).
  • .obsidian/core-plugins.json: enabled/disabled state for built-in plugins.

None of these record a source repository, artifact digest, signature, provenance attestation, build workflow, or verification result. A plugin’s package.json may carry a repository URL, but that file is optional and isn’t trusted validation data. For example, a manifest records version 2.5.0 and author details, and its optional package.json points at https://github.com/author/obsidian-plugin.git, but nothing proves the installed main.js actually came from that repo or a particular commit.

Community plugins are already distributed as GitHub releases, and Obsidian is already recommending Attestations (yay!)

Proposed solution

Roll this out in phases, weakest-but-useful first, and keep every step non-breaking and opt-in.

1. Capture provenance in local plugin data (non-breaking foundation).
At install and on every update, have the client inventory the plugin directory, hash the installed artifacts (main.js, manifest.json, styles.css), retrieve the signed provenance from the release, and record the result locally alongside the existing files. Either extend manifest.json with an optional provenance block or write a sibling .obsidian/plugins/<id>/provenance.json. Suggested fields:

  • source repository, commit or protected/immutable tag
  • artifact digest(s) of the installed files
  • build workflow identity and signing identity (Fulcio cert / OIDC subject)
  • attestation reference
  • verification result and timestamp

Because it’s additive and optional, older Obsidian versions and un-attested plugins just ignore it. Nothing breaks.

2. Keep the trusted history client-side (keep load off the servers).
Store the last trusted release’s provenance locally, so drift checks are a local comparison against what I already accepted, not a server round-trip on every launch. This needs no central cache or new backend, works offline, and is good enough for soft-checks until adoption grows. When adoption is broad enough to justify it, a registry-side attestation index could be layered on, but it shouldn’t be required to ship value now.

3. Surface a trust badge (soft check, opt-in, ship this early).
When the new ‘Verify plugin authenticity’ setting is enabled, show an identifier on the Installed plugins list and in the Update prompt when a release carries verified provenance: an ‘attested’ badge, and where applicable ‘immutable release’. Make it prominent on updates. Informational only, no blocking, but it lets me make a trust decision at the moment it matters. Bonus signal: flag when the previous release was attested too, so I see a consistent track record rather than a one-off. With the setting off (the default until someone turns it on).

Default (opt-in off, nothing changes):

Enabled (opt-in on):

4. Provenance-drift detection on updates (the real protection).
When an update is available, compare its provenance against the locally stored trusted release and check these still match:

  • expected source repository
  • commit or protected/immutable tag
  • build workflow identity
  • signing identity
  • and that the fetched artifact digest matches the attested one

If an update is missing attestation when prior releases had it, or any of the above deviates from the last trusted release, block or quarantine it and tell me exactly what changed. Drift is the signal. A legit author’s repo, workflow, and signing identity are stable release to release; a compromised push usually isn’t.

5. Release-age / cooldown policy. - Stretch Goal, already adopted by NPM and others
Let me set a minimum age before an update is auto-offered (e.g. hold new versions for N days). The Nx Console malicious build was live for ~15 minutes. A short cooldown alone would have protected almost everyone on auto-update.

Why ‘presence of an attestation’ isn’t enough (and why drift-detection is the ask):
In the May 2026 Nx Console compromise (v18.95.0, CVE-2026-48027), attackers used stolen contributor credentials to publish a malicious update under the legitimate publisher identity, and it auto-updated to users. The payload even integrated Sigstore/Fulcio and SLSA tooling to generate valid-looking provenance for downstream artifacts. So a naive ‘has a signature = trusted’ check can be defeated. What catches this is verifying provenance matches the expected repo, protected tag, workflow, artifact digest, and signer, and flagging any deviation from the release you last trusted. Release immutability protects existing artifacts from being swapped; provenance-drift detection plus a release-age policy protect against malicious new versions.

Current workaround (optional)

None that’s real. Restricted Mode disables community plugins entirely (all-or-nothing), and users can manually read release pages, but nobody audits provenance by hand on every update. Auto-update means the compromise usually lands before a human looks.

Related feature requests (optional)

Using this space for ‘eventual additional requests’ to seed the idea of what this build up to

  • Immutable releases for plugin artifacts
  • Per-plugin update controls (pin version, delay updates)
1 Like