From 11ee9a4f1f33fa8ade6612f2f7fc48a6aa223c38 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Fri, 19 Jun 2026 14:01:42 +0100 Subject: [PATCH] fix(update): fail-closed release signature verification When a signature bundle is present, abort the self-update before replacing binaries if cosign verification fails or is unavailable, instead of logging a warning and proceeding. Prevents a malicious/MITM'd release from achieving binary replacement. --- internal/update/update.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/update/update.go b/internal/update/update.go index 342cc13..bac5484 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -254,12 +254,16 @@ func (u *Updater) ApplyUpdate(ctx context.Context, info *UpdateInfo) error { u.setStatus("verifying", 0.2, "Verifying signature...") if info.ChecksumsURL != "" && info.BundleURL != "" { + // Fail-closed: a signature bundle is published for this release, so a + // verification failure (including cosign being unavailable) MUST abort + // the update before any binary is replaced. Silently proceeding would + // allow an unverified binary to overwrite the running one. if err := u.verifySigstoreBundle(ctx, checksumsPath, bundlePath); err != nil { - // Log warning but continue - signature verification is optional if cosign isn't installed - log.Warn().Err(err).Msg("Signature verification failed or skipped") - } else { - log.Info().Msg("Sigstore signature verification passed") + u.setError(err) + return fmt.Errorf("release signature verification failed; aborting update for safety, please update manually with: %s: %w", + GetManualUpdateCommand("v"+info.LatestVersion), err) } + log.Info().Msg("Sigstore signature verification passed") } // Step 3: Download the archive