Follow-up from the security audit of #39 (the civitai upgrade self-updater).
Current state (baseline, acceptable)
civitai upgrade downloads the release tarball + checksums.txt, verifies the tarball's SHA-256 against checksums.txt before replacing the binary (hard-abort on mismatch), and now enforces https + GitHub-host allowlist on all asset URLs (incl. redirect re-validation). So integrity rests on: checksum-verify-before-replace + TLS-to-GitHub.
Gap
checksums.txt itself is not cryptographically signed — its only protection is HTTPS to the GitHub asset host. A full forge of the GitHub API + asset host (or a compromised release) could swap both the tarball and its checksum line and pass the gate. This is the standard goreleaser baseline, but for a command that rewrites the user's binary it's the highest-value hardening left.
Proposed
- Add a
signs: block to .goreleaser.yaml — cosign keyless (Sigstore, signs via the GitHub Actions OIDC identity, no stored private key; verifiable against Rekor + the repo's OIDC identity) or minisign (note: aead.dev/minisign is already pulled transitively by minio/selfupdate).
- Have
civitai upgrade fetch the signature asset and verify the signature over checksums.txt before trusting it (then the existing sha256-of-tarball gate chains off a trusted checksums file).
Acceptance
- Release publishes a signature for
checksums.txt.
civitai upgrade refuses to upgrade if the signature is missing/invalid.
- Unit tests: tampered checksums.txt / bad signature → abort, binary untouched.
Severity: hardening (not a known live vuln; defense against API/asset-host compromise). Tracked separately from #39 which shipped the https/host-allowlist control.
Follow-up from the security audit of #39 (the
civitai upgradeself-updater).Current state (baseline, acceptable)
civitai upgradedownloads the release tarball +checksums.txt, verifies the tarball's SHA-256 againstchecksums.txtbefore replacing the binary (hard-abort on mismatch), and now enforces https + GitHub-host allowlist on all asset URLs (incl. redirect re-validation). So integrity rests on: checksum-verify-before-replace + TLS-to-GitHub.Gap
checksums.txtitself is not cryptographically signed — its only protection is HTTPS to the GitHub asset host. A full forge of the GitHub API + asset host (or a compromised release) could swap both the tarball and its checksum line and pass the gate. This is the standard goreleaser baseline, but for a command that rewrites the user's binary it's the highest-value hardening left.Proposed
signs:block to.goreleaser.yaml— cosign keyless (Sigstore, signs via the GitHub Actions OIDC identity, no stored private key; verifiable against Rekor + the repo's OIDC identity) or minisign (note:aead.dev/minisignis already pulled transitively byminio/selfupdate).civitai upgradefetch the signature asset and verify the signature overchecksums.txtbefore trusting it (then the existing sha256-of-tarball gate chains off a trusted checksums file).Acceptance
checksums.txt.civitai upgraderefuses to upgrade if the signature is missing/invalid.Severity: hardening (not a known live vuln; defense against API/asset-host compromise). Tracked separately from #39 which shipped the https/host-allowlist control.