Container Image Signing and Verification in CI Pipelines
Cryptographic proof that container images came from trusted builds and haven't been tampered with.

A clean pull from GHCR or Docker Hub tells you nothing about where an image came from or whether anyone touched it after it was pushed. That is the structural gap image signing exists to close. Registries store and serve images; they were never built to answer the question of who built a given artifact or whether it matches what left the build system. Tags make this worse because they are mutable: a tag can be moved to point at an entirely different digest with no alert from the registry, no broken link, nothing that would tip off a team pulling myapp:latest that they are no longer getting what they got yesterday.
A vulnerability scan does not close this gap either, because scanning and signing answer different questions. A scan tells you what was inside an image at the moment it was scanned. It says nothing about whether the image you deploy six hours, six days, or six weeks later is the same one. Content and origin are separate properties, and treating a clean scan result as proof of integrity conflates the two.
Layering compounds the exposure. A typical image stacks a base layer, a dependency layer, and an application layer, and each of those can be controlled by a different party entirely: a base image maintainer, an upstream package registry, and the team writing the application code. If any one of those layers is compromised and the image carries no valid signature, the entire workload inherits the risk with no way to detect it before deployment.
The pipeline itself multiplies the number of places this can go wrong. Source, build, packaging, registry, and deployment are each a potential injection point when left unprotected, and the danger isn't abstract. Datadog's own research documents a cryptojacking case where threat actors accessed an exposed Docker API endpoint and used it to deploy containers running scripts that moved laterally between nodes in a cluster. A verified signature check at admission would have stopped that container before it ever ran.
The supply chain attack landscape and the case against passive verification
The pace at which open source supply chain attacks now occur makes manual review or after-the-fact investigation a losing strategy. StepSecurity threat intelligence tracked roughly one such attack every three days starting in March 2026, with a single campaign stealing tens of thousands of secrets in one sweep. At that frequency, a security posture built around checking in when something looks wrong is already behind.
The Shai-Hulud worm, which surfaced in September 2025, marked a turning point documented by ReversingLabs: the first registry-native, self-replicating malware seen in the wild. It compromised hundreds of npm packages across two separate campaigns, and it exposed tens of thousands of downstream GitHub repositories in the process. It propagated directly through the registry rather than through a single poisoned release, so it is the exact threat model that admission-time signature verification was built to stop. A workload that checks for a valid, trusted signature before anything runs does not care how the malicious package spread upstream; it simply refuses to run what was never signed by a trusted identity.
The TanStack incident shows the limits of provenance that isn't tied to enforcement. The compromised packages carried valid SLSA Build Level 3 provenance attestations because they were published through TanStack's own legitimate release pipeline after that pipeline was hijacked. That made them cryptographically indistinguishable from authentic TanStack releases at the point of install. npm provenance, built on Sigstore, would have surfaced the discrepancy had the underlying identity been different from what it claimed to be. The episode stands as a direct precedent for why signing at the container level matters just as much as it does at the package level.
There is also evidence that provenance controls change attacker behavior only when they're required, not merely offered. PyPI introduced opt-in trusted publishing in 2023, and NuGet followed in September 2025. Neither has made the practice mandatory, and no sharp decline in malware has been attributed to either rollout. Attackers route around friction rather than grind through it. A signing program that teams can opt out of protects only the teams that opt in.
Regulation is now adding legal weight to what was already an operational necessity. The EU Cyber Resilience Act's mandatory vulnerability reporting obligations took effect on September 11, 2026. Container runtimes distributed commercially into the EU qualify as products with digital elements under the act, so SBOM generation, vulnerability disclosure, and image hardening are now legal requirements, not voluntary best practice. Full enforcement arrives December 11, 2027, so organizations have a fixed runway to move from passive posture to enforced controls.
Image signing: what it proves and what it does not
Image signing is an integrity and provenance control. It proves that the artifact being deployed is the one a trusted build process produced, and it proves nothing beyond that boundary. A signature confirms who produced an image and whether it has changed since the moment it was signed. That is origin assurance and post-build integrity, full stop as a category of guarantee, not a statement about what the software inside actually does.
Signing does not guarantee that the software inside the container is safe, free of known vulnerabilities, or configured correctly. If a signed image is built from a vulnerable base layer, it's still vulnerable. A pipeline that accepts signatures from the wrong identity, or from any identity at all without checking which one, gains none of the protection signing is supposed to offer, because the policy around the signature matters as much as the signature itself.
Signing works best alongside tools that answer the questions it was never meant to answer. An SBOM tells you what components are present inside the image. SLSA provenance attestations go further than a bare signature by recording build context: which source commit was used, which workflow ran, what inputs were provided. That context lets a verifier confirm not just that a given CI system signed the image, but that the image came from a specific commit run through a specific workflow. Runtime monitoring picks up where signing's coverage ends, watching for suspicious behavior after deployment, since a signature protects only the decision to deploy an artifact, not anything that artifact does once it's running.
Signing sits at the junction between build and runtime. It is the mechanism that confirms the thing being handed from one stage of the pipeline to the next is the thing a trusted process actually produced. That junction only holds if both halves of the equation are enforced: a signature that nobody checks at deployment time offers exactly the same protection as no signature. Enforced end to end, image signing is one of the highest-leverage controls available anywhere in the software supply chain.
Sigstore and Cosign as the mechanism for image signing
Sigstore solves image signing's biggest practical obstacle, which is key management, by removing long-lived private keys from the picture. Its design rests on three components, each handling one part of the problem, and together they produce signatures that are publicly auditable and that cannot be backdated or quietly revoked.
Cosign is the client tool that developers and CI systems actually invoke. It signs and verifies container images and other OCI artifacts, and it stores the resulting signatures as separate OCI objects in the same registry that holds the image, keyed to that image's digest rather than its tag.
Fulcio is the certificate authority behind the signature. Instead of issuing a certificate to a person's long-lived key, Fulcio issues short-lived signing certificates tied to an OIDC identity, like a GitHub Actions workflow identity or a GitLab CI job token. The certificate ties the signature to a specific, verifiable identity at a specific moment, not to a key sitting on a laptop or a build server somewhere.
Rekor is the append-only transparency log that records every signing event that passes through Sigstore. Because the log is public and cannot be edited after the fact, a signature can't be manufactured retroactively for a tampered artifact unless the attacker also controls the OIDC identity that was active at the time of the original build. Rekor was rebuilt as a tile-based Rekor v2 in October 2025 specifically to handle scale without sacrificing that guarantee.
Keyless signing has become the default choice for most CI environments for a simple reason: there's no long-lived private key sitting on a runner or a developer's machine for an attacker to steal. The trust anchor is the OIDC identity the CI platform issues at build time, and that identity is ephemeral by design, gone as soon as the job completes.
Docker retired Docker Content Trust, and that is pushing teams that relied on it toward open standards like Sigstore as the natural successor. Major registries including Docker Hub, ECR, and Google Artifact Registry support Cosign verification natively as of 2026, which removes one of the larger adoption barriers teams faced when the tooling was newer. Sigstore graduated from OpenSSF in March 2024, and it now backs npm provenance, PyPI attestations, Homebrew provenance, and GitHub Artifact Attestations, making it the closest thing the open source ecosystem has to a shared standard for artifact signing.
During verification, always check the signature against the image digest, never the tag, because a tag can be reassigned to a different digest after signing while the digest itself cannot change. Tags are mutable and can be reassigned to point at a different digest at any time. Only the digest is immutable, and only an immutable reference can anchor a cryptographic signature meaningfully.
Choosing the right signing trust model before writing any pipeline code
This decision determines who holds custody of keys, how auditable the signing process will be, how rotation gets handled, and whether the whole setup can even function in the target environment. Getting this wrong does not produce a bug; it produces a signing program that can't survive contact with the organization's actual infrastructure.
Keyless OIDC signing, Sigstore's default mode, fits cloud-native CI environments that have reliable outbound access to Fulcio and Rekor, whether that's the public Sigstore instances or a private deployment of the same components. Its advantage is that there's no long-lived key to manage, rotate, or protect at all, since the signing identity is the CI platform's own OIDC token and that token expires on its own. Its constraint is equally direct: it needs Fulcio and Rekor to be reachable at the moment of signing, so it doesn't work in an air-gapped environment without standing up a private Sigstore deployment first.
KMS-backed Cosign signing, using something like HashiCorp Vault's Transit secrets engine, fits a different set of constraints: regulated environments, air-gapped deployments, and teams that need explicit custody of private keys or hardware-backed key storage through an HSM. Its advantage is that keys never leave Vault's protected boundary. Signing happens server-side through an API call, every signing action gets logged with who performed it, when, and which image was involved, and the short-lived tokens used by CI runners limit how long any single credential stays dangerous if exposed. Even a fully compromised CI runner cannot extract the private key when Vault sits behind it as the signing backend, because the runner never holds the key to begin with.
Neither model solves enterprise key management by itself, and most teams underestimate that. Cosign and Sigstore solve the mechanics of producing and verifying a signature. If signing keys end up sitting on developer laptops or CI runners anyway, they're exposed to precisely the kind of compromise signing exists to prevent. If every team in an organization manages its own keys independently, there's no central audit trail and no consistent rotation or revocation policy, undermining the standardization a signing program is meant to provide.
The decision in practice comes down to a short set of questions about the environment. If the build environment has reliable outbound internet access and you don't need hardware-backed key custody, keyless signing is the lower-overhead default, so start there. Neither option is more advanced than the other; they are built for different constraints, and most teams are well served by whichever one matches the environment they actually run.
Signing the image at build time in CI where placement matters
Signing has to happen immediately after the image is pushed to the registry and before any promotion or deployment step runs. The earlier a signature gets created, and the later it gets verified, the stronger and longer-lasting the provenance guarantee it carries.
The canonical order looks the same across CI systems: build the image, push it to the registry, sign the image digest with Cosign, optionally attach a SLSA provenance attestation, then verify the signature at any downstream promotion gate. Signing happens after the push step specifically because Cosign signs the digest of an already-pushed image, and that digest doesn't exist as a stable, addressable reference until the image is sitting in the registry. Signing has to precede deployment because the whole point is to compress the window of exposure: sign as close to build time as possible, verify as close to runtime as possible, and the gap between those two moments is the span during which an image could be swapped or altered undetected.
A GitHub Actions workflow using keyless signing illustrates the mechanics concretely. The workflow grants the id-token: write permission so the runner can request an OIDC token from GitHub's identity provider. After the image is pushed, a command resembling cosign sign --yes <registry>/<image>@<digest> sends that OIDC token to Fulcio, receives back a short-lived certificate, signs the digest, and records the event in Rekor. The identity embedded in that certificate is the workflow's OIDC subject, typically the repository name and workflow path, and that identity becomes the exact claim an admission controller checks later: not just "is this signed," but "was this signed by the workflow we expect."
A Jenkins pipeline backed by HashiCorp Vault follows a similar sequence, but the custody model it relies on is different. The Jenkins job authenticates to Vault with a short-lived token, Cosign is invoked with a reference to the Vault Transit key rather than a local file, and the actual signing operation happens server-side inside Vault so the private key never touches the CI runner at any point in the process.
Attaching SLSA provenance attestations to extend what the signature proves
A signature alone answers one question: did a trusted process produce this artifact. A SLSA provenance attestation answers a more detailed question than that one: which source commit was used, which workflow ran, and what inputs were provided to produce it. Attaching that attestation alongside the Cosign signature, as the canonical pipeline order places it right after signing and before the downstream verification gate, means a verifier isn't just confirming that a trusted CI system signed an image. The verifier can confirm the image was built from a named commit, by a named workflow, with a defined set of inputs, which is exactly the layer of specificity the TanStack incident showed can still be missing even when provenance attestations are present and technically valid. The attestation turns a signature from a yes-or-no check into a record detailed enough to answer the next question an auditor, a regulator, or an incident responder will actually ask.
Sources
- Signing and verifying container images with Cosign and Sigstore - Security Boulevard
- Secure your container images with signature verification
- Migrating from Docker Content Trust to Sigstore
- Why Image Signing Does Not Prove the Image Is Vulnerability-Free
- How to Use Image Signing with Cosign and Sigstore in Kubernetes Pipelines
- How to Sign Container Images with Cosign
- Verifying Signatures - Sigstore
- Overview - Sigstore


