Signed SLSA provenance exists, but a release tarball was swapped after the build. What catches it?
answer
- detective, not preventive
- hash the bytes again yourself
- subject digest binds artifact to build
- verify where you consume, not where you build
- a signature nobody checks is decoration
basics
~20 sOnly verification at the point of use catches it. Recompute the digest of the bytes about to be deployed and match it against the provenance subject digest, after checking the envelope signature and the builder identity.
solid answer
~50 sNothing about the level itself catches it - verification does. Say a cloud admin replaces an infrastructure module tarball in the release bucket while the published provenance still describes the honest earlier bytes. Signed provenance from Build L2 or L3 does not prevent that write; it makes the swap **detectable**, because the statement binds one specific digest to one specific build, and different bytes hash differently. Detection happens only where somebody actually verifies: fetch the artifact, recompute its digest, compare it to the statement's subject digest, validate the signing envelope, and confirm the identity behind it is the builder you expect and the predicate's build definition matches policy. If deployment installs whatever is in the bucket without that check, the signing bought an audit record and nothing else. Put the check at the consuming boundary, in a trust domain the person who can write to the bucket does not control.
code
json · 14 lines{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "network-baseline-1.4.2.tar.gz",
"digest": { "sha256": "9f2c...e1" }
}
],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": { "buildType": "...", "externalParameters": { "...": "..." } },
"runDetails": { "builder": { "id": "https://builds.example.com/hosted" } }
}
}go deeper
Know that a provenance statement names its artifact by cryptographic digest, so bytes that were changed afterwards will no longer match it.
Explain why this is detection rather than prevention, and list what a verifier checks: envelope signature, signer identity, subject digest against the bytes, then predicate against policy.
Show where you place the check in a real delivery path, how you handle the window between fetching an artifact and using it, and what a mismatch triggers.
Own the call to make verification blocking, and be able to argue the cost of failed deploys against the value of catching a post-build swap - including who is allowed to change the policy.
## Preventive versus detective, stated precisely The first thing to get right is the direction of the claim. SLSA does not stop anybody from overwriting an object in a bucket - that is an access-control question, and the person in the scenario has legitimate console rights. What signed provenance changes is that the swap can no longer happen **silently**. The statement names the artifact by cryptographic digest, and the substituted bytes will not hash to that digest. So the control is detective, and like every detective control it only fires if something is looking. That is the whole point of the question. Signing without verification changes nothing about your exposure; it changes only what an investigator can reconstruct afterwards. ## What binds the statement to the bytes A provenance statement carries a `subject` array, each entry naming an artifact and a digest map. That digest is the join between "a claim about a build" and "the file in my hands". ## The four checks a verifier must perform A verification step that only asks "is there a valid signature?" fails in practice. All four of these have to hold: 1. **Envelope signature valid.** The payload is carried in an envelope signed separately from the statement it wraps, so this is its own check. 2. **Signer identity is the expected builder.** A valid signature from an unexpected identity passes check 1 and fails the policy. Pin the builder identity you accept; do not accept "some trusted-looking key". 3. **Subject digest matches the bytes.** Recompute the hash of the artifact you are about to use and compare. This is the check that catches the bucket swap, and it is the one most often skipped because the artifact and its attestation were fetched together and look consistent. 4. **Predicate matches policy.** The build definition, source location and builder identity recorded in the predicate should be the ones you expect for this artifact - not merely present. ## Where the check has to run Place verification **at the consuming boundary**, immediately before the bytes are installed, applied or deployed, and inside a trust domain the party who can write to the release location does not control. Two common placements fail: - **Verifying only in the pipeline that produced the artifact.** That proves the build agrees with itself. The threat in the scenario happens strictly after the build finishes. - **Verifying at fetch and then using a cached copy later.** The window between fetch and use is unguarded, and on long-lived agents it can be substantial. Verify the bytes you are actually about to execute. A third, subtler failure: running verification with a policy that the same operator can edit. If the person who can swap the artifact can also relax the policy that would have caught it, you have moved the control rather than added it. ## "But the attacker could swap the attestation too" They can - and it does not help them, provided the signing material is not theirs to use. Overwriting the attestation object gives them an envelope they cannot sign under the builder's identity, so check 2 fails. This is precisely why the level matters here even though verification does the catching: at Build L2 the signing authority is the hosted platform rather than the producer's build, and at L3 the signing material is out of reach of user-defined build steps, so a person with storage rights or a compromised build cannot mint a fresh, matching statement. Co-locating the artifact and its attestation is therefore acceptable; what would not be acceptable is a signing key the same operator can read. ## The asset actually at stake In this scenario the asset is not customer data - it is **audit truth and control-plane integrity**. An infrastructure module applied by a deployment system runs with the credentials of that system. A swapped module can rewrite network rules or grant roles, and the published provenance would still describe the honest earlier build, so your records would say the deployment was clean. That is what makes a mismatch such a high-value signal: a verification failure here is not a nuisance, it is an incident, and it should page rather than warn. ## Making the control real Three operational decisions turn this from a diagram into a defence. First, verification is **blocking** - a mismatch stops the deployment; an advisory-only check will be muted the first time it is noisy. Second, mismatches are **alerted and investigated**, not retried; the natural instinct on a failed check is to re-pull, which discards the evidence. Third, the verifier's expected-identity policy is **owned and change-controlled** by a different team than the one that can write to the release location, so no single compromised operator holds both halves. Say all of that and you have answered the real question, which is not "which level" but "where does the check live, what does it compare, and who could turn it off".
- Besides "the signature is valid", what must the verifier check?Three more things. That the statement's subject digest equals the digest of the bytes you are about to use; that the identity behind the signature is the builder you expect rather than merely a valid signer; and that the predicate's build definition and source location match policy. A valid signature from an unexpected builder passes the first check and should still fail the deployment.
- Where would you place verification for artifacts pulled from a release bucket?At the consuming boundary, immediately before the bytes are applied or deployed, and in a trust domain the person who can write to the bucket does not control. Verifying inside the pipeline that produced the artifact only proves the build agrees with itself, and verifying at fetch then using a cached copy leaves the fetch-to-use window unguarded.
- Does storing the attestation next to the artifact weaken this?Not on its own. The attestation's value comes from the signature and the identity behind it, not from where it sits, so an operator who overwrites it produces something they cannot sign as the builder. What would break the control is a signing key that same operator can read - then both objects are forgeable and co-location stops mattering.
- Should a failed verification block the deployment or warn?Block, and page. A digest mismatch on a release artifact has no benign explanation worth deploying through; it means the bytes are not the ones the recorded build produced. Advisory-only checks get muted after the first noisy week, and the instinct to re-pull and retry destroys the evidence you would need for the investigation.
saying these in an interview costs you the question
- Says SLSA prevents post-build tampering
- Assumes signing alone protects the artifact
- Verifies the signature but never the subject digest
- Runs verification only inside the build that signed
- Accepts any valid signature without pinning the builder identity