Skip to main content

Trust Model

Plugins run inside the SSG dashboard — same origin as the daemon, same access to /api/json/*, same window. The trust model has to make that safe.

What gets verified at install

When a user runs ssg plugins install <id> (or clicks Install in the dashboard marketplace), the daemon performs four independent checks before any plugin code is extracted to disk:

#CheckFailure mode
1manifest_url is on an allow-listed host (raw.githubusercontent.com or hub.sigmashake.com)Refuse install.
2SHA-256 of the downloaded .tar.gzmanifest.artifact_sha256Refuse install.
3Ed25519 signature over artifact_sha256 verifies against manifest.signing_fingerprintRefuse install.
4manifest.signing_fingerprint ≡ the hub-recorded author_public_key for the packRefuse install.

Check #2 ensures the tarball wasn't swapped on the CDN. Check #3 ensures only the key holder could have produced this artifact. Check #4 anchors the key to a specific GitHub identity in the hub — so even if attacker-controlled GitHub infra served a different artifact, the signing key cross-check would fail.

The four checks are independent: any one of them passing doesn't help an attacker bypass the others. All four must pass.

Why GitHub releases

Plugin artifacts live on GitHub release assets because:

  • GitHub gives every publisher a stable, content-addressable URL that doesn't require us to operate object storage.
  • GitHub's tag-based versioning matches plugin semver naturally.
  • Publishers already have an identity (GitHub login) the hub uses for attribution.

The hub does not mirror plugin artifacts. If a publisher takes down a release, that version becomes uninstallable. This is intentional — plugin authors retain the right to unpublish.

Publisher keys

Every plugin author signs with one Ed25519 keypair, generated and stored locally:

~/.sigmashake/keys/signing.key # private key (mode 0600)
~/.sigmashake/keys/signing.pub # public key (SPKI)

The private key never leaves the machine that ran ssg keys generate. To publish from a second machine, copy ~/.sigmashake/keys/ to it manually — do not re-run ssg keys generate on the second machine (that produces a new key, which won't match the one your hub account has registered).

The corresponding public key is uploaded to the hub via ssg keys register. The hub stores it under your GitHub identity (users.public_key column). At plugin install time, the daemon refuses to install if the manifest's claimed signing_fingerprint doesn't match the public key on file for the plugin's listed author.

Key rotation

If your signing key is compromised:

  1. Stop publishing from the compromised machine immediately.
  2. Generate a new key on a clean machine, then re-register it with the hub (ssg keys generate followed by ssg keys register).
  3. Open a support ticket (ssg support) so the old key can be revoked from the hub. The hub keeps an audit log of every key rotation.
  4. Re-publish each of your plugins under the new key. Users will see signature mismatches on ssg plugins install until they uninstall + reinstall the updated artifact.

What plugins can and cannot do

Plugins run inside the SSG dashboard origin (http://127.0.0.1:5599). They:

  • ✅ Can call /api/json/* endpoints with the dashboard token
  • ✅ Can fetch from any remote URL (CORS rules apply)
  • ✅ Can persist client-side state via localStorage
  • ❌ Cannot register new server-side routes (v1)
  • ❌ Cannot read or write outside their own /plugins/<id>/ namespace
  • ❌ Cannot access the user's filesystem directly
  • ❌ Cannot escalate to root or modify SSG's signing keys

That said, the dashboard origin is trusted by the daemon. A malicious plugin could in principle make authed requests to /api/json/eval, /audit, or any other endpoint. That's why the verification chain matters: a plugin is only as trustworthy as its signing key.

The threat we don't defend against

We don't sandbox plugins from each other or from the host dashboard. That means: don't install a plugin you don't trust the publisher of. Treat plugins the way you'd treat a VS Code extension or a Chrome extension — vet the author, check their reputation, prefer plugins from publishers you recognize.

Future versions will add an iframe sandbox + capability manifest so plugins can declare and prompt for the permissions they need. Until then, the publisher's signing key + GitHub identity is what you're trusting.

Audit trail

Every plugin install/uninstall is recorded in ~/.sigmashake/audit.db with:

  • Plugin id + version
  • signing_fingerprint (so you can later verify which key was trusted at install time)
  • Source pack id (hub) or local path (sideload)
  • Timestamp

You can review this from the dashboard's Activity tab, or with ssg audit search --decision=plugin_install.

See also