Skip to content

Harden self-update trust with signed checksum manifest #143

@vriesdemichael

Description

@vriesdemichael

Summary

The current bb update flow verifies release archives against sha256sums.txt, which protects against corruption but not against a release-host compromise where both the archive and checksum file are replaced.

This issue proposes a minimal trust-hardening change:

  • keep the current release archives, checksum file, and GitHub provenance attestations
  • add a signed checksum manifest artifact to each release
  • teach bb update to verify the checksum manifest signature before trusting it

Current State

Relevant current behavior:

  • release workflow builds cross-platform archives and publishes sha256sums.txt
  • release workflow already generates GitHub provenance attestations
  • bb update downloads sha256sums.txt, downloads the release archive, compares the archive hash to the checksum entry, and replaces the installed binary

This is better than no verification, but the updater currently trusts an unsigned checksum file fetched from the same release source as the artifact.

Problem

If an attacker can modify the official release contents, they can replace:

  • the release archive
  • sha256sums.txt

The current updater would still accept the malicious archive because the checksum file itself is not authenticated.

GitHub provenance attestations help with manual verification and auditability, but they are not currently the trust signal used by bb update.

Proposed Change

Implement a minimal hardening step while leaving most of the current system unchanged.

Release pipeline

Keep the existing release process, and add one new artifact:

  • sha256sums.txt.sig or sha256sums.minisig

The release workflow should:

  • continue generating sha256sums.txt
  • sign the checksum manifest with a dedicated signing identity
  • upload the signature artifact with the release
  • continue generating GitHub provenance attestations

Updater

Change bb update from:

  1. download checksum file
  2. trust checksum file
  3. verify archive against checksum
  4. replace binary

to:

  1. download checksum file
  2. download checksum signature
  3. verify checksum file signature using an embedded public key
  4. verify archive against checksum
  5. replace binary

Scope

What should stay the same:

  • release archive names and formats
  • sha256sums.txt
  • current archive extraction and binary replacement flow
  • existing GitHub provenance attestations

What should change:

  • release workflow signs the checksum manifest
  • updater verifies the signed manifest before using it
  • docs explain the updater trust model more clearly

Why This Approach

This keeps the implementation small and targeted.

Checksums remain useful for integrity.
Signatures add publisher authentication for the updater.
Attestations remain useful for provenance, human verification, CI, and enterprise/audit scenarios.

This avoids redesigning the updater around attestation APIs while still materially improving trust.

Security Notes

This does not fully solve a malicious-publisher or compromised-signing-key scenario.
It does improve the common and important case where the release host or release publication path is compromised but the signing authority is not.

To reduce remaining risk over time:

  • separate signing authority from release publication credentials
  • prefer a dedicated signing identity or service
  • keep self-update explicit and user-invoked
  • continue recommending package-manager installs where appropriate

Acceptance Criteria

  • release workflow publishes a signed checksum manifest alongside sha256sums.txt
  • bb update refuses to trust unsigned or invalidly signed checksum manifests
  • bb update continues verifying archive hashes before replacement
  • existing GitHub provenance attestations remain in place
  • installation/update docs explain the distinction between checksums, signatures, and attestations

Open Design Choice

Pick one signing mechanism for the checksum manifest, for example:

  • minisign
  • cosign
  • another simple verifier appropriate for embedding in the Go client

Preference should go to the smallest reliable implementation that keeps updater bootstrap complexity low.

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions