Skip to main content
View Markdown ↗

Copy this page

Select and copy the Markdown below, then paste it into your LLM.

On this page

Verify a downloaded release before you install it

More projects now publish a Sigstore bundle (a .sigstore.json file) next to each release binary. The bundle carries the signature, the short-lived signing certificate and the transparency-log proof. It does not tell you whether the signer is the one you expected. That part is yours: a valid signature from the wrong identity is still a valid signature.

cilock verify-bundle checks a bundle under the Sigstore client verification procedure and refuses to run without an expected identity and issuer. In this session the prompt asks Claude to check a cosign release before installing it, and to take the expected signer from Sigstore's documentation rather than from the bundle.

How this was recorded

TestifySec wrote both prompts and sent them into the session. Claude Code and cilock ran unedited, and the recording was not changed afterwards.

A Claude Code session downloading cosign v3.1.3, verifying its Sigstore bundle with cilock verify-bundle, then showing a one-bit change and a wrong signer identity are both rejected

Download terminal recording (.cast)

What happens, step by step

  1. Find the expected signer somewhere other than the bundle. Claude sends a subagent to read Sigstore's installation docs ("Verifying Cosign Releases", for cosign 3.x), which name the signer as [email protected] with the issuer https://accounts.google.com. Reading the identity out of the bundle and then checking the bundle against it would prove nothing.

  2. Download the release and its bundle. cosign-darwin-arm64 and cosign-darwin-arm64.sigstore.json from the v3.1.3 GitHub release, with curl.

  3. Verify.

    cilock verify-bundle --bundle cosign-darwin-arm64.sigstore.json \
      --certificate-identity [email protected] \
      --certificate-oidc-issuer https://accounts.google.com \
      cosign-darwin-arm64

    cilock prints Verified OK and exits 0. It fetched the public-good Sigstore trusted root over TUF, because no --trusted-root was given.

  4. Stop before installing. Claude reports the SHA-256 and the install command and waits. A second prompt asks for proof the check can fail first.

  5. Change one bit. A copy with one bit flipped at offset 1,000,000 is refused: invalid signature when validating ASN.1 encoded signature.

  6. Expect the wrong signer. The real binary checked against [email protected] is refused: expected SAN value "[email protected]", got "[email protected]". Claude adds a test of its own: the right identity with the GitHub Actions issuer is refused too, because the identity and the issuer must both match.

What the verification requires

cilock verify-bundle requires every check the trusted root can back:

CheckWhat it rules out
Signature over the file's digesta changed or swapped binary
Exact certificate SAN (--certificate-identity)a valid signature from someone else
Exact OIDC issuer (--certificate-oidc-issuer)the same identity string minted by a different provider
SCT, when the root distributes CT logsa certificate the CA never logged
Transparency-log entry, when the root distributes Rekor logsa signature that was never publicly recorded
Signing time from a TSA timestamp or a log inclusion promisea signature made outside the certificate's lifetime

Neither --certificate-identity nor --certificate-oidc-issuer can be empty, and both are exact matches. For a bundle signed with a managed key, pass --key with the PEM public key instead. The artifact can be a file path or a digest such as sha256:<hex>.

Where to get the identity

For a release built in GitHub Actions the identity is usually the workflow path at a tag, for example https://github.com/acme/app/.github/workflows/release.yml@refs/tags/v1.2.0, with the issuer https://token.actions.githubusercontent.com. Take it from the project's documentation or security policy, not from the bundle you are checking.

Run it yourself

The recording used cilock built from main at commit 5b614726; the verify-bundle command ships in CI/lock 4.6.0 and later. Verification needs network access to fetch the Sigstore trusted root unless you pass --trusted-root with a local trusted_root.json.

To record your own evidence about a build rather than check someone else's signature, see Release gates and Signing and identity.

Reference generated from the product documentation. Match commands and support details to your installed release.