Skip to content

Enforce trust anchor for non-sideloaded installs#23

Merged
TeoSlayer merged 1 commit into
mainfrom
security/trust-anchor-non-sideloaded
Jun 22, 2026
Merged

Enforce trust anchor for non-sideloaded installs#23
TeoSlayer merged 1 commit into
mainfrom
security/trust-anchor-non-sideloaded

Conversation

@TeoSlayer

Copy link
Copy Markdown
Contributor

Problem

scanInstalled ran only VerifySignature on the catalogue (non-sideloaded) path. Signature validity proves integrity, not trust: a manifest self-signed by any key passed the check and was spawned. The trust regime was effectively backwards — a non-sideloaded (catalogue) app should get the FULL trust-anchor check, while sideloading is the explicit local opt-out.

Fix

The non-sideloaded branch now also calls VerifyTrustAnchor() against the trusted-publishers list. Sideloaded apps (.sideloaded marker) keep skipping the publisher chain and instead satisfy the sideload allow-list, unchanged.

Test

TestScanInstalled_UntrustedPublisherWithoutMarkerRejected: a manifest with a valid self-signature from a fresh untrusted key, no .sideloaded marker, is refused. Confirmed it fails without the fix and passes with it.

Test helpers now sign with a fixed publisher key pinned into TrustedPublishers via TestMain (set once, never mutated — race-free under -race), so existing catalogue-path lifecycle tests still represent legitimate trusted apps.

Validation

GOWORK=off go build/vet ./... clean; go test -race ./... green.

scanInstalled ran only VerifySignature on the catalogue (non-sideloaded)
path, so a manifest self-signed by any key was accepted and spawned.
Signature validity is integrity, not trust: a non-sideloaded install
must also pass VerifyTrustAnchor against the trusted-publishers list.
Sideloading remains the explicit local opt-out of this chain.

Add a regression test: a validly self-signed manifest from an untrusted
publisher, with no .sideloaded marker, is refused.
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@TeoSlayer TeoSlayer merged commit 0513e62 into main Jun 22, 2026
5 checks passed
@matthew-pilot matthew-pilot deleted the security/trust-anchor-non-sideloaded branch June 22, 2026 15:48
Alexgodoroja pushed a commit that referenced this pull request Jun 23, 2026
…tatic list)

Addresses review on #25: keep the anchor mechanism, but anchor it to the
release-signed catalogue (the root of trust) instead of a static, env-populated
publisher allow-list that nothing populated (so #23 enforcement skipped every
catalogue app).

- Manifest.VerifyTrustAnchor(cataloguePublisher string): confirms Store.Publisher
  equals the publisher key the catalogue pins for the app. Empty/unpinned =>
  fail-closed. (Symbol kept, repointed — no silent self-signed acceptance.)
- Remove the unused package-global manifest.TrustedPublishers.
- Config.CataloguePublisher(appID) (pub string, pinned bool): the daemon supplies
  this from the catalogue it has signature-verified with CatalogPubkey.
- Supervisor catalogue path: VerifySignature + VerifyTrustAnchor(cataloguePin).
  nil provider or unpinned app => fail-closed (not spawned). Sideload unchanged.

Tests: full accept/mismatch/unpinned/nil-provider matrix (-race green), plus the
repointed manifest unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants