Signing Nix-Generated SBOMs With Sigstore Cosign
Nix's hermetic builds and Cosign's keyless signing create verifiable software supply chain evidence.

Signing Nix-generated SBOMs with Sigstore Cosign turns a detailed dependency inventory into verifiable supply chain evidence. Nix supplies the declared, hash-pinned inputs. Cosign binds the resulting document to an artifact and a signing identity. The guarantee depends on the whole chain, from reviewed build inputs through signing to deployment-time verification.
Why unsigned SBOMs fall short as supply chain evidence
An SBOM documents dependencies, but it cannot by itself prove who produced the document or whether someone altered it afterward. It describes an attack surface but does not prove provenance. For an auditor or deployment system, that leaves a basic evidentiary gap between a list of components and a trustworthy account of a particular release. A signature supplies the missing integrity and identity checks, provided verification binds it to the expected producer and artifact.
The EU Cyber Resilience Act requires machine-readable SBOMs for products with digital elements, and the first reporting obligations take effect on 11 September 2026. That reporting date is distinct from the broader application of the Act’s main obligations. Cosign supports both SPDX and CycloneDX, so either format can enter the signing workflow. The inventory being signed still needs to be checked for an accurate description of the build.
Why Nix dependency graphs make unusually complete SBOM source data
Nix gets dependency information from its build model, so it does not rely only on inspecting a build after it finishes. Every package’s source is checked against a cryptographic hash specified in its definition. Builds then execute in a sandbox without network access, preventing undeclared dependencies from entering through network downloads. The inventory starts from declared inputs as well as the components that an inspection tool happens to recognize.
Because Nix tracks runtime and build dependencies, its closure provides a rich basis for recording licenses, source provenance, and patches. Those details support both risk assessment and compliance review. The applicative-systems/secure-supply-chain repository demonstrates this approach through a NixOS image definition with verifiable source inputs. The image can be rebuilt offline from scratch, yielding an auditable source-only closure suitable for regulatory review.
Under v0.1, hermetic builds with declared inputs were strict requirements for Level 4, while reproducibility was recommended on a best-effort basis. The current Build track tops out at Level 3. The measured 95 percent reproducibility rate across NixOS packages in the distributed GNOME version supports the practical case for Nix, but does not by itself establish a pipeline’s SLSA level. Even a rich closure may have gaps in vulnerability-database coverage, which needs to be checked separately downstream.
The flake.lock commitment that makes a Nix SBOM trustworthy before signing begins
A committed flake.lock is the prerequisite for making this dependency graph stable across builds. With the same flake.nix and lock file, builders get the same dependency versions, down to the commit or content hash in the record. That gives the SBOM a reproducible input basis. If the lock file is outside version control, the build loses that determinism, even if its output gets a valid signature later.
The trust model must account for flake input poisoning before signing. A pipeline that runs nix flake update automatically can change the inputs it is about to build without a deliberate review of those changes. A floating reference to the nixpkgs master branch also leaves input resolution open to attack at evaluation time, before sandboxing takes effect. An inventory signed after a build with compromised inputs is still an authentic record of compromised material.
The operational rule is to commit flake.lock with flake.nix and treat updates as deliberate, reviewed changes outside automatic CI execution. This separates dependency maintenance from release execution. It also gives reviewers a concrete input change to assess before the pipeline creates evidence about the resulting artifact. Teams that already follow that practice can add signing without changing how they choose their dependency versions.
How Cosign's keyless signing model works and why it eliminates the main operational objection
Long-lived signing keys mean more work for teams, which must store, protect, and rotate them. Cosign’s keyless model removes that persistent key-management problem by using the CI job’s OIDC identity as its signing credential. The identity becomes the verification anchor. Instead of asking whether an artifact was signed by possession of a standing secret, a verifier can ask whether the expected workflow produced the signature.
Cosign uses that token with Fulcio, Sigstore’s certificate authority, to obtain a short-lived signing certificate bound to the workflow identity. It then signs the artifact digest. Rekor, the public transparency log, records the signing event with an inclusion proof. The certificate expires after use, leaving no long-lived signing key for the team to store or rotate.
Cosign’s specifications support the in-toto predicate model, allowing the SBOM to be attached as a structured, signed claim associated with the artifact. For image-signature payloads, Cosign supports Red Hat’s simple signing format, which binds the manifest digest. The payload’s image-reference field is present but ignored by Cosign. The digest is the content address that counts. A mutable tag such as latest is not an adequate substitute, because its target can change after signing without changing the tag itself.
Attaching a signed Nix-derived SBOM as a Cosign attestation in CI
The SBOM should be generated as soon as the Nix build produces its closure, before the image is pushed or deployed. That ordering ties the document to what the build actually produced. Registry attachment follows when the artifact is available there. The important boundary is between deriving evidence from the build and publishing that evidence against the artifact digest.
The build runs hermetically and produces its Nix store outputs. The next step derives an SPDX or CycloneDX document from the closure. If the build emits an OCI image, Syft can also operate on that image. Vulnerability scanning then consumes the SBOM file. Scanning the document rather than the image allows an old release to be assessed against new CVE data without pulling its layers again. Teams still need to check which identifiers the scanner can match, especially Nix-native package identifiers.
The cosign attest command attaches the SBOM as a signed in-toto attestation predicate to the registry artifact. SLSA provenance and the SBOM remain separate attestation types because they make different structured claims. Verification must then constrain the signing identity. The --certificate-identity option pins the expected repository, workflow path, and ref, while --certificate-oidc-issuer pins the identity provider. Without those constraints, successful verification establishes only that some workflow signed the artifact, leaving its authorization as the release workflow unverified.
Keeping the attestation with the registry artifact also makes the inventory available without requiring full image-layer downloads. This is useful for Nix’s distroless OCI output. A minimal image can still have a rich dependency closure, and the attached document gives security tools access to that information independently of the image’s size.
Enforcing signed SBOM attestations at deploy time with Kubernetes admission control
A signature that is never checked remains documentation. Kubernetes admission can make it a gate that blocks workloads when their images lack the evidence the policy requires. Sigstore’s policy-controller and Kyverno support identity-based verification of Cosign signatures. They can reject pods before execution when an image does not have a valid signature from the required identity. This puts the verification decision at the boundary where an artifact would become a running workload.
The policy needs an image reference pattern, an expected OIDC issuer, and an expected subject representing the authorized workflow. The subject must be specific to that workflow within GitHub Actions. Otherwise, the policy accepts too broad a class of signers. The same enforcement pattern can require a valid SBOM attestation in addition to an image signature. That distinction makes the dependency document a condition of deployment.
For teams outside Kubernetes, the minimum viable enforcement is a cosign verify step in the deployment script, configured to fail closed. Where the requirement includes a signed SBOM, verification must also cover that attestation. An image signature alone does not establish that the dependency inventory is present. The deployment rule and the evidence it checks must express the same requirement.
The CVE-scanning gap in Nix SBOMs and how to bridge it
A correctly signed and enforced Nix SBOM can still produce incomplete vulnerability results. Major vulnerability databases do not index against Nix package URLs, so scanners such as Grype can return little or nothing for Nix-native components. The missing matches are a coverage problem. They do not demonstrate that the components are free of known vulnerabilities, and successful signature verification does not change the scanner’s ability to recognize them.
Reconstruction-based bridging addresses this mismatch by mapping Nix packages back to upstream ecosystem equivalents. Conventional CVE databases can then match the reconstructed identities for ecosystems including npm, PyPI, and Go. Those packages reconstruct most reliably. Native C and C++ packages are harder to map, and purely Nix-native packages still have no mapping.
Treat Nix SBOM scan results as a floor and add ecosystem-specific scanning. Signing establishes the document’s provenance and integrity. Scanning asks whether recognized components match known vulnerability records. Neither step substitutes for the other. The Manifest Platform’s automated vulnerability mapping for Nix packages represents an actively developing approach to improving that visibility. It aims to close the identification gap without assuming that reproducibility on its own keeps vulnerable dependencies out of a build.
What environment-level reproducibility adds to the signed SBOM workflow
A signed SBOM records what a build contained, while a declarative build environment records the conditions under which it was produced. Another builder needs those conditions to meaningfully reproduce the result. Tool versions can differ across CI runners, local environments can diverge from CI, and patches can exist outside version control. In those circumstances, a signature may remain valid for the original artifact without describing what a future build will produce. Artifact integrity and repeatable production are distinct guarantees.
Version-controlling the full toolchain with the source code makes the environment available for reproduction by developers, CI runners, and auditors. It also gives rollback a broader scope. Reverting the environment manifest reverts the whole declared toolchain, including the application’s dependencies. An input-derived environment hash can also be attached to deployments, supporting rapid CVE discovery and hash-level blocking or patching without log-grepping or image rescanning.
SLSA v1.0 defines Build Levels 1–3, with Level 4 deferred, so the older Level 4 terminology should not stand in for a current assurance claim. Signed outputs and declarative environments help meet the trust goals behind the Build track, but having them does not by itself prove that every requirement is met. For platform engineering teams, the practical goal is a base environment that includes SBOM generation and signing by default. Each project then gets the workflow with its infrastructure, without having to set it up separately.


