DEV Community

Your build attestation is a chain of custody, not a safety certificate

Dimitris Kyrkos on November 05, 2026

Picture a release with a perfect paper trail. You have the reviewed commit, the resolved dependencies, the builder identity, the artifact digest, a...
Collapse
 
analista_83 profile image
Sammi De Blas •

Attestation proves provenance, not correctness. A chain of custody is only as strong as the key rotation behind the signing step, so the useful question is how often the pipeline can verify the whole chain end to end rather than just the last link.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Absolutely, and key management is an important part of that trust chain. If signing keys are compromised or poorly rotated, even the provenance itself becomes questionable. End-to-end verification should be routine, not something teams only think about during an incident. But even a perfectly verified chain still brings us back to the original point: it proves where the artifact came from, not whether the code does what it's supposed to do.

Collapse
 
analista_83 profile image
Sammi De Blas •

Rotating the signing key matters as much as the signature. An old key still trusted makes the chain look clean.

Thread Thread
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

That's a good point. Rotation alone isn't enough if old keys remain trusted indefinitely. There needs to be a clear process for revocation, expiration and checking which keys were valid when an artifact was signed. Otherwise, the signature can remain technically valid while the trust behind it has already expired.

Collapse
 
kaj_ilands profile image
Kaj •

Failure mode 5 is the one nobody here has picked up yet, and it's the same bug as your webhook.

The unsigned request that skips the check, and the field that skips the redaction, are one failure wearing two hats: a guard that only covers what somebody remembered to list. if (sig) means "check everything except the case where there is no sig." A redaction step built from field names means "mask everything except the fields that did not exist when the list was written" - a new SDK, a tool that starts recording file paths, a header somebody adds next sprint.

Making the list longer does not fix a list-shaped guard. To find out it is already broken: put one sentinel string into every client-supplied surface at once (the prompt, an env var, a filename, a user field), run one release, then read the record back from the store itself and grep the raw bytes. If the sentinel shows up anywhere, the redaction is decoration. Then leave a canary in the prompt as a standing gate, so the next field that gets logged trips it.

I have watched this find a header nobody listed coming back verbatim from a store whose policy named, in good faith, every field it masked.

Section 4 has the same shape. artifact_digest in the record is a statement about the artifact, not a measurement of it. A verifier that compares that string against another value in another record proves the record is self-consistent. Only recomputing the digest from the bytes answers whether the artifact matches the thing you shipped.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

That's a really good catch. I hadn't connected the two failure modes quite that way, but you're right. Both are examples of relying on an explicit list of things we know about instead of testing what happens when something unexpected appears. I especially like the sentinel approach because it tests what actually ends up stored, not just what the redaction code claims to do. The digest point is equally important: verifying a claim in an attestation isn't the same as independently verifying the artifact.

Collapse
 
alexshev profile image
Alex Shev •

A provenance record answers where an artifact came from; it does not answer whether the source or its behavior was safe.

The strongest workflows keep those questions separate: attest the build inputs and environment, then pair that evidence with policy checks, tests, and an explicit release decision.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Exactly. Keeping those questions separate is the important part. Attestation tells us what went into the artifact and how it was built. Tests and policy checks tell us something about its behavior, but even those depend on what we choose to test. The release decision needs to consider the gaps too.

Collapse
 
rdin777 profile image
rim dinov •

Spot on, Dimitris! This is a crucial distinction that often gets blurred in DevSecOps discussions. Build attestation proves provenance (who built it, from what source, with what tools), but it says absolutely nothing about the inherent safety of the code itself.
In the Web3 space, we see this exact gap. A team might have a perfectly attested, OIDC-secured CI/CD pipeline (proving the chain of custody is intact), but a developer could still accidentally commit a hardcoded test key or introduce a subtle logic flaw. The attestation will happily sign off on that vulnerable artifact.
This is why attestation must be paired with automated, context-aware security gates in the pipeline. In my work, I build custom Slither detectors that run as a hard fail in CI/CD. The attestation proves the detector ran in a trusted environment, but the detector is what actually validates the safety of the smart contract.
Curious to hear your take: As attestation frameworks (like SLSA) become more standard, do you see security teams struggling with 'scanner fatigue' from false positives, or is the real bottleneck still just getting teams to adopt the attestation infrastructure in the first place?

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

I think the bigger bottleneck is still getting teams to adopt the infrastructure and, more importantly, understand what each layer actually guarantees. Scanner fatigue is definitely real, though. If teams get flooded with false positives, they eventually start treating security gates as another checkbox rather than something worth investigating.

I like your Slither example because it highlights the distinction nicely. The attestation gives you confidence that the checks ran in a trusted environment, while the detector provides a separate layer of evidence about the code. Neither replaces the other. I think the real challenge is making these layers work together without turning the pipeline into noise.

Collapse
 
paullovelace profile image
Paul Lovelace •

The missing-signature webhook is the perfect example — the attestation is accurate, the artifact is exactly what was built, and the invoice still gets marked paid. Failure mode 3 is the one I'd put on a wall: approved_by is a fact about a click, not a record of scrutiny. Do you find teams actually change anything once they see that distinction, or does the green checkmark keep winning the argument?

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

I think it depends on whether the distinction leads to a concrete change in the release process. Most teams agree with it in principle, but the green checkmark is hard to challenge when deadlines are tight. What helps is turning vague approval into specific questions about risky behavior. Instead of just asking who approved the PR, ask what failure cases were actually examined. That's where review starts becoming meaningful rather than procedural.

Collapse
 
marcusykim profile image
Marcus Kim •

I'd strengthen the missing-signature test with a side-effect assertion: capture the invoice's state, send the unsigned webhook, then assert it is still unpaid (or that markInvoicePaid was never called). A handler could mutate the invoice and return 401 afterward, so the status-only test would pass despite violating the requirement. That gives the review question in failure mode 3 a concrete invariant: rejected requests must leave payment state unchanged.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Absolutely. That's an important improvement to the test. Checking only the HTTP status can give us a false sense of security if the side effect has already happened. The real invariant is that a rejected request must leave the invoice state untouched. I'd argue that's exactly the kind of test that makes code review more meaningful because it verifies the actual business requirement, not just the response the handler returns.

Collapse
 
alexshev profile image
Alex Shev •

A provenance record answers where an artifact came from; it does not answer whether the source or its behavior was safe.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Well put. I'd only add that the distinction matters most when things go wrong. A provenance record can help us trace exactly what shipped, but it shouldn't become a convenient way to claim that the release was properly reviewed or safe. Those are different responsibilities.