skip to content

Your build already publishes an SBOM for every artifact. What does a build provenance attestation tell a consumer that the SBOM cannot, and what does verifying one actually check?

level: seniorimportance: should knowfreq 32%

answer

  1. contents versus process
  2. anyone can write a document
  3. the statement is bound to a digest
  4. whose signature, not just a valid one
  5. fail closed or it is decoration

basics

~20 s

An SBOM lists what is inside an artifact; provenance is a signed statement about how the artifact was produced — which builder, which source repository and commit, which parameters. Verification checks that statement against a policy, bound to the artifact's digest.

solid answer

~50 s

They answer different questions. An SBOM is an inventory — components, versions and identifiers — so you can ask "does anything I ship contain this vulnerable library" or "what licences am I distributing". It says nothing about origin: an SBOM is a document, and anyone can write one. Provenance is a signed statement *about the build*: the builder's identity, the source repository and commit it built from, the build entry point and parameters, bound to the artifact's digest as the statement's subject. It answers "did this really come out of our pipeline, from our main branch". Verification means more than "the signature is valid": you fetch the attestation for the digest you are about to run, confirm the signature chains to the builder identity you expect, and check the claims — repository, ref, builder ID — against a policy that rejects the artifact otherwise. Unverified provenance is decoration.

code

json · 19 lines
json
{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    { "name": "myapp", "digest": { "sha256": "9f2b0c8a1d4e6f37b2c5a90d1e8f4b6c3a7d29e0f15b8c4a6d3e2f7b9c0a1d4e" } }
  ],
  "predicateType": "https://slsa.dev/provenance/v1",
  "predicate": {
    "buildDefinition": {
      "buildType": "https://example.com/buildtypes/pipeline/v1",
      "externalParameters": {
        "repository": "https://example.com/acme/myapp",
        "ref": "refs/heads/main"
      }
    },
    "runDetails": {
      "builder": { "id": "https://example.com/ci/builder/v1" }
    }
  }
}

go deeper

for a junior

Know the one-line split: an SBOM lists what is inside an artifact, provenance records how and where it was built. Do not claim either one proves the other.

for a middle

Explain that provenance is a signed statement bound to the artifact's digest, naming the builder, source repository and ref, and that an SBOM carries no origin claim at all unless it is itself attested.

for a senior

Describe verification as policy evaluation — expected builder identity, expected repository and ref, matching subject digest, fail closed — and name the common failure of generating attestations nobody checks.

for a principal

Own the rollout question: enforcement at the deployment boundary will block legitimate builds on day one, so decide which artifact classes are gated first, what the exception path is, and who owns the policy.

## Two documents, two questions Teams that have adopted SBOMs often assume provenance is the same idea with more ceremony. It is not. - **SBOM** — *what is in this thing.* A structured inventory of components with versions and identifiers, typically in CycloneDX or SPDX format. Its consumers are vulnerability response ("which of our artifacts contain this library?") and licence compliance. - **Provenance** — *where this thing came from.* A statement describing the build that produced the artifact: who built it, from what source, how. A useful way to hold them apart: the SBOM describes the *contents*, the provenance describes the *process*. An attacker who tampers with your build can produce a perfectly accurate SBOM of their tampered artifact. Provenance is what makes tampering visible, because forging it requires the builder's identity rather than just a text editor. ## What a provenance statement contains The common format is an in-toto attestation: a signed envelope wrapping a statement that binds a **subject** (the artifact, identified by digest) to a **predicate** (the claim being made about it), where the predicate type names the schema — for build provenance, the SLSA Provenance predicate. ```json { "_type": "https://in-toto.io/Statement/v1", "subject": [{ "name": "myapp", "digest": { "sha256": "9f2b0c…" } }], "predicateType": "https://slsa.dev/provenance/v1", "predicate": { "buildDefinition": { "buildType": "…", "externalParameters": { "repository": "…", "ref": "refs/heads/main" } }, "runDetails": { "builder": { "id": "…" } } } } ``` The two structural points that matter more than the field names: the statement is **bound to a digest**, so it cannot be transplanted onto a different artifact; and the **builder identity** is part of the claim, so "a valid signature" is meaningless until you say *whose* signature you require. ## What verification actually means A verifier that only checks "the signature parses and validates" has verified nothing useful — anyone can sign anything with their own key. Real verification is a policy evaluation: 1. **Locate** the attestation for the exact artifact digest you are about to deploy or run. 2. **Authenticate** it — the signature chains to an identity, and that identity is *the builder you expect*, not merely a valid one. 3. **Evaluate the claims** — does the recorded source repository match the repository you believe owns this artifact? Is the ref a release branch or tag rather than an arbitrary contributor branch? Is the build entry point the one you sanctioned? 4. **Fail closed** — an artifact with no attestation, a mismatched claim, or an unknown builder is rejected, not warned about. Step 4 is where most programmes quietly fail. Generating provenance is a checkbox a pipeline can tick in an afternoon; enforcing it at the point of deployment is an organisational commitment, because on day one it will block something legitimate. ## How the two documents work together They compose. The strong pattern is to attach the SBOM to the artifact **as an attestation too** — a signed statement whose subject is the same digest. That fixes an ignored weakness of standalone SBOMs: an unsigned SBOM sitting next to an artifact can be swapped, edited or simply be about a different build. Once it is attested, "this inventory belongs to this exact artifact and was produced by this builder" is verifiable. It also helps with a second common defect: an SBOM generated from the source manifest lists what the project *declares*, whereas one generated from the built artifact lists what actually shipped — system packages pulled in by the base image, vendored files, tools left in the final layer. When incident response asks "are we affected", the manifest-derived inventory can be confidently wrong. Generating from the finished artifact, at the point where its digest exists, and attesting both together is what makes the pair trustworthy. ## Honest limits Provenance is an *integrity* claim, not a *quality* claim. It tells you the artifact came from your pipeline and your repository. It does not tell you the code was reviewed, the dependencies were sane, or the build was not itself compromised through a poisoned input. Likewise an SBOM tells you a component is present, not that it is reachable or exploitable. Presented as guarantees, both invite the criticism that they are paperwork; presented as what they are — a verifiable answer to "what is in it" and "where did it come from" — they are the two facts you desperately want during an incident.

  • Why is an unsigned SBOM published next to an artifact weaker than an attested one?
    Because nothing binds it. An unsigned SBOM is a file anyone can replace, edit, or accidentally publish from a different build — and it carries no statement of who produced it. Attesting it makes the inventory a signed claim about one specific artifact digest by one specific builder, which is what turns it from documentation into evidence.
  • A pipeline generates provenance for every artifact, but nothing downstream checks it. What has been gained?
    Forensics, and little else. You will be able to reconstruct after the fact which build produced a given artifact, which is genuinely useful during an incident. But no attack is prevented, because an attacker who substitutes an artifact simply substitutes its attestation too. The control only bites when something refuses to run an artifact that fails policy.
  • Why can an SBOM generated from the source manifest disagree with what actually shipped?
    Because the manifest records declarations, not results. The finished artifact also contains whatever the base image supplied, transitively resolved versions, vendored code and build tooling left behind. During vulnerability response that gap produces both false negatives and false confidence, which is why the inventory should be derived from the built artifact.

saying these in an interview costs you the question

  • An SBOM proves where the artifact came from
  • Provenance is just a signature on the artifact
  • Verification means the signature parsed successfully
  • Generating attestations is the control; checking them is optional
  • Provenance proves the code was reviewed and safe

context