Key insight
If the running container cannot tell you which source produced it, the chain of custody has already failed. A nine-byte field in a JSON response is the difference between an audit conversation that takes five minutes and one that takes three weeks.
The three questions every customer eventually asks
The first question is always operational: what version is running, right now? An on-call engineer needs to know whether the symptom they are seeing is in the latest release or in the one they meant to deploy yesterday. Without a quick answer, the next thirty minutes are spent on archaeology rather than on the incident.
The second question is procurement’s: what source produced this binary? When a new vulnerability is announced in a dependency, somebody has to confirm whether the agent in the customer’s tenant contains the affected version. Without a source pointer that an engineer can resolve in seconds, the response timeline starts in days.
The third question is audit’s: has anything been altered between the source and the binary? This is the question a compliance review asks once per year, in writing, with a deadline. Either you can hand them a signed-build attestation that demonstrates a clean chain, or you spend a fortnight reconstructing one from log lines.
The three questions are answered by three correspondingly small artefacts: a version endpoint, an image digest with a build provenance, and a signed-build attestation. None of them is expensive. All of them are catastrophic to add retroactively.
Tags lie. Digests do not.
The most common mistake in chain-of-custody design is treating a container tag as if it identified the binary. It does not. A tag is a mutable pointer. The string v1.2.3 in your registry can be re-pushed to a new image any time without any record. Two customers running “v1.2.3” one week apart may be running different binaries.
A container digest, on the other hand, is a cryptographic hash of the image manifest. It cannot be reused or re-pushed. The string sha256:e8a4… identifies exactly one set of layers, forever. Two customers running the same digest are running the same bits, full stop.
Every chain-of-custody design that survives audit treats tags as human-readable labels and treats digests as the actual identity. The version endpoint reports both, but only the digest can be used for forensic comparison.
The /version endpoint
One small unauthenticated endpoint on the running agent answers the operational question and seeds the other two. It returns a JSON document containing, at minimum:
- The human-readable semantic version of the release.
- The short and full source revision hash that produced the binary.
- The UTC timestamp of the build.
- The image tag and digest in the registry.
Producing those values is the build pipeline’s job, not the application’s. The pipeline injects them at image-build time, typically as build arguments that become environment variables on the running container. The application reads them at start and returns them when asked.
Two implementation rules matter. First, the endpoint must work without authentication — a customer on-call engineer must not need a token to find out what is running. Second, the endpoint must not return anything sensitive. Version metadata only, never request bodies, never tenant data, never internal IP addresses.
If you need more than these four fields, add them. Three useful extras are: the dependency-lockfile hash for the language stack, the build pipeline run identifier, and the deployment timestamp (which is not the build timestamp). The deployment timestamp helps distinguish “the build is correct but a rollout failed” from “the build itself is wrong”.
The User-Interface signature line
The same four fields belong on the application’s user interface, in a small footer line, in fixed-width type. v1.2.3 · e8a4f01 · 2026-06-02 14:32 UTC. The cost is minutes; the operational pay-off is enormous. Customers report incidents accurately. On-call engineers do not have to ask for the version because the user already pasted it. Screenshots from production are self-contained.
The footer line is also a useful test that the build pipeline actually injected the metadata. If the footer reads unknown · unknown · unknown, the build pipeline lost the variables and the release should be considered broken even if the application starts up.
Build provenance: making the binary self-describing
The version endpoint tells you what is running. Build provenance tells you what is in it. The current industry standard for build provenance is an in-toto attestation generated to the SLSA framework: a signed JSON document that names the builder identity, the source revision, the dependencies pulled, and the steps executed.
For container images, the attestation is pushed to the registry alongside the image, as a sibling artefact. Any tool that can read the registry can verify both that the image was produced by the expected builder identity and that the build steps match what your pipeline definition claims. The verification step is one command. The customer’s audit team can run it themselves; you do not need to be involved.
SLSA defines four levels of provenance. For most tenant-deployed agents in 2026, level 2 is the realistic target — provenance is generated by a hosted build service, signed, and pushed automatically. Level 3 (hardened build platform) is appropriate for regulated industries. Level 4 is rarely necessary outside national-security workloads.
The SBOM
A Software Bill of Materials is an inventory of every dependency the image contains, by name, version, and licence. The two prevailing formats are CycloneDX and SPDX; either is acceptable. The SBOM is generated at build time, signed, and attached to the release as a downloadable artefact.
The customer’s vulnerability-management team uses the SBOM to correlate the agent against new CVEs without re-scanning the binary. A new disclosure for a dependency is a one-grep operation; the answer is either “yes, version 1.2.3 ships libfoo 4.5.6” or “no, that dependency is not present”.
An SBOM the customer cannot download is, for operational purposes, no SBOM at all. The SBOM file lives on the release page; its URL is recorded in the pin file (chapter 4); the customer can pull it on day one.
What the customer’s audit team verifies, in practice
- Hit
/versionon the running agent. Capture the digest and the source revision. - Pull the image manifest from the registry. Confirm its digest matches what
/versionreported. - Pull the signed-build attestation from the registry. Verify the signature against your published build identity. Read the source revision out of the attestation. Confirm it matches the value from
/version. - Download the SBOM from the release page. Confirm its checksum matches the value in the pin file.
Each step is a one-line command. The four-step sequence either passes or fails cleanly. There is no narrative reconstruction, no email chain, no “trust us”.
What it costs you to get this right
On a new project, building these artefacts in costs a day of pipeline work and a small amount of application code — the version endpoint, the user-interface footer, three build-time environment variables. On an existing project that has shipped a few releases without them, retrofitting costs perhaps a week, most of which is migrating consumers of the old :latest tag to digests. On a project that has shipped many releases without them, retrofitting is a multi-week project because every customer has to be re-onboarded onto the new identification model.
The pattern across teams is consistent: the cost rises faster than the value of the project does. Build the chain on the first release.
References & further reading
- SLSA framework specification, all levels. slsa.dev/spec
- in-toto attestation framework, including the build-provenance predicate. in-toto.io
- OCI Distribution Specification — the registry behaviour that makes digests immutable. opencontainers/distribution-spec
- CycloneDX SBOM specification. cyclonedx.org
- SPDX SBOM specification. spdx.dev
- NIST Secure Software Development Framework (SP 800-218) — the “Respond to Vulnerabilities” practices that assume an SBOM exists. csrc.nist.gov/Projects/ssdf