This is part three of Ship the Proof. The first two parts established that a release is a content digest and that the digest, not a branch, is the candidate you promote. This part is about the surprise that hits the moment you act on that: the evidence you attached to a digest does not travel with it the way you assume.

You sign your images. You generate a software bill of materials. You attach build provenance. Then you promote the image from your build registry to your production registry, by digest, the obvious way, and the deploy-time verification gate rejects it because none of the evidence is there. The image arrived. The signatures, the bill of materials, and the provenance did not.

This is one of the most common ways an otherwise correct supply-chain setup quietly fails, and it reduces to a single fact about how attestations attach to images.

The invariant: evidence is a separate object, joined by a back-reference

When you sign an image or attach a bill of materials, the result does not become part of the image. It becomes a separate manifest that points back at the image through a subject field. The OCI distribution specification defines subject as “an association from one manifest to another, typically used to attach an artifact to an image,” and you discover what is attached to a digest by querying the registry’s referrers API, which returns “a list of descriptors” each carrying “a subject field that specifies the value of” the target digest (OCI distribution-spec).

The mental model that gets people into trouble is “the signature is on the image.” It is not. The signature, the bill of materials, and each attestation are independent manifests sitting next to the image in the same registry namespace, linked to it only by a back-reference. Picture a constellation of signed claims all pointing at one digest, rather than a single bundle you can move as a unit.

Hold that picture, because it dictates the one property your promotion step has to satisfy.

The trap: a naive copy moves a stranger

Now promote that image. The naive instinct is a plain image copy by digest, the kind of copy that moves only the manifest you named.

That copy does exactly what you asked. It transfers the image. It does not transfer the referrers, because they are separate manifests you did not name. They stay behind in the source registry. The image lands in the destination clean and naked, and its signature, bill of materials, and provenance are orphaned in the registry you copied from.

Everything still looks fine until the deploy gate runs. At admission, the policy asks the destination registry for the image’s attestations, the registry has none to return, and the gate fails closed, correctly, because a missing attestation is a rejection. The evidence never arrived. You spend an afternoon convinced the signing step is broken when the signing step worked perfectly. The copy dropped the evidence on the floor.

The property a promotion step must provide

State it without naming a tool: a promotion must be referrer-aware (it moves the image and every manifest whose subject is that image), and it must verify at the destination after the copy, failing closed if the evidence did not arrive. Two requirements, and any implementation that satisfies both is acceptable.

Here is one implementation that satisfies them. With Sigstore’s cosign, a referrer-aware copy is cosign copy with an explicit allow-list of what to bring along:

cosign copy --only=sig,att,sbom "$SRC_IMAGE" "$DST_IMAGE"

The --only flag takes a “comma delimited” list, “ex: --only=sig,att,sbom,” covering signatures, attestations, and SBOMs (cosign copy options). The point is not the specific tool. The point is that the copy names the evidence deliberately. A recursive oras cp -r is another implementation of the same property.

Two cautions turn “be referrer-aware” into “be explicit and verify your target,” and both are reasons not to trust defaults.

First, do not depend on implicit copy behavior. A regression in cosign v2.2.1 caused cosign copy to stop copying signatures by default, and a user reported they “could no longer verify signatures on prod images because the signatures were missing” (sigstore/cosign#3379). That is a single user-reported issue, not documented behavior, but it is a concrete reason to pass the allow-list explicitly rather than rely on a default that can change under you.

Second, an OCI 1.1 referrers advertisement on a registry does not guarantee a working recursive referrer push. As of 6 March 2026, Amazon ECR returns “405 Method Not Allowed” when an OCI 1.1 referrer manifest is pushed via recursive copy, and the workaround of dropping recursion “successfully copies the image but excludes referrers, which breaks supply-chain attestation workflows” (aws/containers-roadmap#2783). Validate referrer portability against your actual target registry before you trust it.

Verify at the destination, and fail closed

Copying the referrers is half the job. The other half is proving they arrived, and that the artifact is what it claims to be, before the promotion is allowed to succeed. Make the promotion conditional on a verification run against the destination digest after the copy, and make that verification fail closed.

Failing closed is not a stylistic preference. Sigstore’s guidance is blunt about why: a verification system “must be carefully designed to work correctly if an attacker can delete or hide any specific attestation,” and therefore “your systems should be designed to fail closed rather than open” (cosign verify-attestation). A missing attestation aborts the promotion. It never defaults to accept. An attacker who can strip an attestation must not thereby buy a pass.

A non-zero exit from the destination verification stops the promotion job outright. Then confirm independently that the referrers actually landed, by listing what is attached to the destination digest. If the destination shows the signature, the bill of materials, and the attestation, and the verification passes, the promotion preserved the full evidence chain.

The rule to carry away

An image and its attestations are separate objects in the registry, joined only by a back-reference. Move the image alone and you have moved a stranger. Move the image and its referrers, then verify at the destination and fail closed if anything is missing, and the thing that lands in production is the thing you actually vouched for.

This property does not enforce itself. The same verification has to run again at the boundary where the image is actually admitted to the cluster, because a promotion gate protects the registry-to-registry hop but not the cluster. The next part is about putting that check at the one boundary every deployment must cross.

Sources