Join our Newsletter — 33% off our NHI Course
Home› Guides› Code Signing vs Artifact Attestation: What Each Proves…
Guide Application Security

Code Signing vs Artifact Attestation: What Each Proves About Your Software

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 17 min read
On this page

A valid code signature proves that a publisher's key approved a file, not that the file was built from the source the publisher thinks it was, and the biggest supply chain compromises of the last decade shipped with perfectly valid signatures. Artefact attestation, in the form of signed in-toto statements such as SLSA build provenance, answers a different question: which build platform produced this exact digest, from which repository and with which parameters. This guide compares the two as evidence: what each proves, how keys and identities are held, how a verifier checks each at install or deploy time, and how each fails. It is written for application security, platform and release engineers deciding what to require from internal builds and from suppliers. Signing operations are covered in the Code Signing Security Guide and the provenance format in the SLSA and Build Provenance Guide; this page is about choosing and combining them.

Key takeaways

  • They answer different questions. A code signature answers "who vouched for these bytes?"; a provenance attestation answers "how, where and from what were these bytes built?". Neither substitutes for the other.
  • A stolen key defeats code signing completely. Anyone holding the private key produces signatures indistinguishable from the publisher's, which is why custody, approvals and timestamp rules matter more than the algorithm.
  • Attestation shifts trust from a key to a builder identity. With keyless signing, the attestation is signed with a short-lived certificate bound to a workload identity, and the verifier pins that identity rather than a long-lived key.
  • Verification policy is where both succeed or fail. A signature check that accepts any valid certificate, or an attestation check that does not compare source and parameters to expectations, verifies almost nothing.
  • Most mature programmes require both. Platform-native signatures (Authenticode, Apple notarisation, package registry signatures) remain the install-time trust anchor for users, while attestations drive internal deploy gates and supplier assurance.

The short answer

Use code signing whenever software reaches a platform or user that enforces signatures: Windows, macOS, mobile stores, firmware boot chains, Linux package managers. Use artefact attestation whenever you control the verifier, such as a Kubernetes admission controller, an internal artefact registry or a release promotion step, and want to know that an artefact came from your approved pipeline rather than from a laptop or a compromised runner. Require both for anything you ship externally: the signature satisfies the platform, the attestation lets you and your customers check the build. The Provenance Attestation vs SBOM guide covers the next question, what to attach alongside provenance.

What each one proves

Question a verifier asksCode signature (Authenticode, GPG, package signature)Artefact attestation (in-toto statement, SLSA provenance)
Have the bytes changed since signing?Yes: the signature covers a hash of the file or a signed catalogue of hashesYes: the statement's subject lists the artefact digest, and the envelope is signed
Who vouched for it?The holder of the private key, named in a certificate issued after CA identity vetting (or a self-managed key such as GPG)The signing identity of the attestation, typically the build platform or a workload identity in a CI system
Which build system produced it?Not statedrunDetails.builder.id, which the verifier looks up in its roots of trust
From which source and revision?Not statedRecorded in buildDefinition.externalParameters and resolvedDependencies
With what build inputs?Not statedexternalParameters, which verifiers compare to expected values and reject when unrecognised
When was it signed?From an RFC 3161 timestamp countersignature, if one was appliedFrom the build metadata and, with Sigstore, the transparency log entry time
Does the operating system enforce it natively?Yes, on Windows, macOS, iOS, Android and in UEFI Secure BootNo: enforcement is by tools you deploy (CLI checks, admission controllers, registry policies)

The SLSA v1.2 build provenance specification (status: Approved) defines the provenance predicate with the type https://slsa.dev/provenance/v1. buildType, externalParameters and builder.id are required at Build L1; internalParameters and resolvedDependencies are optional. The in-toto Attestation Framework, currently v1.2, wraps the predicate in a Statement that binds it to a subject, inside an authenticated Envelope. Anatomy is covered in the in-toto Attestations Guide.

Threat model: what each stops and misses

Code signing

  • Stops: tampering in transit or on a download mirror, unsigned malware masquerading as a vendor binary, and modification of installed files where the platform re-checks signatures.
  • Misses: anything injected before the signing step. The SolarWinds Orion compromise is the reference case: a tool the attackers placed in the build environment injected the SUNBURST code into builds without changing the source repository, and the tampered builds went out between March and June 2020 as normal, signed updates. See SolarWinds Supply Chain Compromise.
  • Fails outright when the key leaks. After Lapsus$ published two NVIDIA code signing certificates with their private keys in 2022, signed malware appeared within days. Both certificates had expired, but Windows accepts expired certificates for driver signing, and revoking them would have broken legitimate drivers, so Microsoft pointed customers to Windows Defender Application Control policies instead. See NVIDIA Code-Signing Certificates Stolen.
  • ATT&CK: T1553.002 Code Signing (adversaries signing their own payloads) and T1588.003 Code Signing Certificates (obtaining them) describe the abuse; M1045 Code Signing is the mitigation entry.

Artefact attestation

  • Stops: artefacts built on a developer machine or unapproved runner and pushed to a registry, builds from a fork, branch or tag you did not expect, builds with injected parameters, and substitution after the build (the digest stops matching).
  • Misses: malicious code committed to the expected repository, a malicious dependency the build legitimately resolved, and tampering inside a trusted builder that can still sign. SLSA Build L3 hardening (isolated builds, signing material the build steps cannot reach) narrows that last gap but does not remove it.
  • Identity theft replaces key theft. Sigstore's own security model states that a stolen OIDC token lets an attacker obtain a certificate for that identity and sign. The design makes this detectable through certificate and Rekor transparency logs rather than preventing it, and detection depends on someone monitoring those logs.
  • ATT&CK: T1195.002 Compromise Software Supply Chain and T1554 Compromise Host Software Binary describe the behaviours provenance checks aim to make visible. See the MITRE ATT&CK T1195 Supply Chain Compromise page.

Key custody and keyless signing

The two disciplines differ most in what has to stay secret, for how long.

AspectTraditional code signingKeyless attestation signing (Sigstore model)
Secret to protectA long-lived private key, often valid for over a yearAn ephemeral key held in memory for one signing operation, plus the CI workload identity that obtains the certificate
Storage ruleCA/Browser Forum Code Signing Baseline Requirements (v3.11.0) require publicly trusted code signing keys to be generated, stored and used in a suitable hardware crypto module, effective 1 June 2023Nothing stored at rest; the risk moves to the OIDC token and the CI configuration that can request it
Certificate lifetimePublicly trusted certificates issued on or after 1 March 2026 must not exceed 460 days, per the same requirementsFulcio issues short-lived certificates, so revocation is avoided; the verifier checks the signature was made while the certificate was valid
Proof of signing timeRFC 3161 timestamp from a timestamp authorityRekor transparency log entry, whose signed tree gives a verifiable time
Compromise responseRevoke, reissue, re-sign, and often ship client updates that trust the new keyDisable or narrow the identity, then search the transparency log for every entry made with it
What the verifier pinsA certificate chain, publisher name or public keyA certificate identity (for example a workflow path and ref) and the OIDC issuer

The cost of a long-lived key compromise shows in HashiCorp's 2021 response after its GPG key, used to sign the SHA256SUMS files for product downloads, was exposed through CI environment variables during the Codecov incident. HashiCorp revoked the key, validated and re-signed existing releases, and shipped Terraform patch releases so the tool would trust the new key for provider verification. See HashiCorp GPG Key Exposure. The trade-offs between the two signing models are covered in depth in Keyless vs Key-Based Code Signing; note that attestations can be signed with a managed key too, and that choice is independent of whether you produce attestations at all.

Architecture in words

Code signing pipeline: the build produces an artefact; a signing service, ideally separate from the build and backed by an HSM or cloud KMS, receives a hash, applies policy (who requested it, which project, was it approved), signs, and adds a timestamp. The signed file carries its signature (embedded, as with Authenticode, or detached, as with a signed checksum file or a catalogue file). The operating system or package manager verifies the chain to a trusted root at install or run time.

Attestation pipeline: the build platform, not the build script, records what it ran and generates the provenance. In GitHub Actions, for example, the actions/attest action (documented at v4) needs the workflow permissions id-token: write, contents: read and attestations: write, plus packages: write for container images. The attestation is stored beside the artefact (in an OCI registry as a referrer, or in the platform's attestation store), and a verifier you operate fetches and checks it before promotion or admission. GitHub documents artifact attestations for public repositories on all current plans and for private or internal repositories on GitHub Enterprise Cloud.

Verification at install and deploy time

Both controls are only as strong as the check at the far end. The SLSA "verifying artifacts" procedure gives the attestation side in three steps, and the code signing side has an equivalent.

  1. Check the cryptography. For signatures, the hash matches and the chain reaches a trusted root, with a valid timestamp if the certificate has since expired. For attestations, the envelope signature verifies against your roots of trust, the statement's subject digest matches the artefact, and the predicateType is exactly https://slsa.dev/provenance/v1.
  2. Check the signer is the one you expect. For signatures, pin the publisher or the specific certificate, not "any trusted CA". For keyless attestations, pin both identity and issuer: cosign verify takes --certificate-identity and --certificate-oidc-issuer, and the GitHub CLI's gh attestation verify takes the expected repository with -R. Look up builder.id to decide which SLSA Build level the builder is trusted for; SLSA says an unknown builder gets no more than L1.
  3. Check expectations (attestations only). Compare builder identity, canonical source repository, buildType and externalParameters with what this artefact should have, and reject unrecognised parameters, as the SLSA specification directs.
  4. Fail closed on absence. An artefact with no attestation should be rejected the same way as one with a bad attestation. With the Sigstore policy-controller, an attestation entry with a predicateType but no policy block only checks that the attestation exists; add a CUE or Rego policy to check its contents.
  5. Record the decision. Log the digest, the identity accepted and the policy version, so incident responders can later answer "what did we admit that was signed by X?".

Failure modes compared

FailureEffect on code signingEffect on attestationControl
Signing key or token stolenAttacker signs anything as the publisher until revocation, and longer where expired certificates are still honouredAttacker can sign as the stolen identity; entries appear in the transparency logHSM custody and approvals; narrow OIDC trust (repository, ref, environment); log monitoring
Build environment tamperedMalicious build is signed normallyProvenance is honest about the builder but cannot see inside it unless the platform isolates buildsIsolated, ephemeral builders (SLSA Build L3); reproducible rebuilds for critical artefacts
Verifier too permissiveAny certificate from any trusted CA acceptedIdentity regex matches every repository in the organisation, or no expectations checkedPin exact identities; peer review policy changes
Missing evidence acceptedUnsigned scripts or containers allowed throughImages without attestations admittedFail closed; time-boxed exceptions with owners
Signing as a rubber stampAny developer can sign any fileAny workflow, including on pull requests, can request attestationsRestrict signing to release workflows and protected branches

Decision criteria

  • Who verifies: if the verifier is an operating system or app store, you need platform code signing; if the verifier is you or a customer with tooling, attestation gives far richer evidence.
  • What you are defending against: tampering after release favours signing; tampering inside or around the build favours attestation with an isolated builder.
  • Offline and air-gapped consumers: traditional signatures with timestamps verify offline easily; keyless verification needs a trusted root and log material shipped with the artefact (a Sigstore bundle) or a private instance.
  • Organisation size: a small team on a hosted CI platform can get provenance by adding a step and pinning one identity; a large organisation with many build systems needs a register of trusted builders and a central policy store before attestation adds value.
  • Supplier assurance: asking suppliers for signed provenance tied to digests gives better evidence than a questionnaire answer that "builds are secure". The Code Signing Buyer's Guide lists questions for signing platforms themselves.

Where identity fits

Both models are non-human identity problems. A code signing key is a privileged machine credential: it should have a named owner, an inventory entry, hardware custody and a rotation plan, and every signing request should be attributable to a pipeline identity. In the keyless model the CI workload's OIDC identity is the credential, so the security of attestation depends on how tightly the federation trust is scoped: which repository, which branch or tag, which environment. Treat changes to that trust as you would a change to a production signing key. The Compromised Code Signing Certificate Playbook covers response when either kind of credential leaks.

Worked scenario: a SaaS vendor that also ships an agent

A vendor runs a containerised SaaS platform and ships a Windows endpoint agent to customers. Its Windows agent is Authenticode signed through a signing service backed by a cloud HSM, with two-person approval for release signing and RFC 3161 timestamps. Its containers are built on hosted CI.

  1. Agent: keep Authenticode, because Windows and customer application control policies (such as WDAC rules keyed to the publisher) depend on it. Add SLSA provenance for the agent binary, signed by the CI workload identity, and publish it, so security-conscious customers can verify that the signed binary came from the release workflow on a protected tag.
  2. Containers: attest every image in the release workflow, then deploy the policy-controller with a ClusterImagePolicy that pins the issuer and the release workflow identity and requires the SLSA provenance predicateType, with a Rego policy checking the source repository.
  3. Rollout: run the policy in warn mode on namespaces labelled policy.sigstore.dev/include=true for two weeks, fix the images that warn, then switch to enforce one namespace group at a time.
  4. Result: a stolen developer token can no longer push a runnable image to production, because it cannot produce provenance from the release workflow; a stolen Authenticode key remains the highest-impact credential, so it stays in hardware with approvals.

Implementation path

  1. Inventory: list every signing key, certificate and signing identity, and every place that verifies signatures today (and every place that should but does not).
  2. Fix code signing custody first: move keys into an HSM or KMS-backed signing service, remove keys from CI variables, require approvals for release signing and timestamp every signature. The Code Signing Policy Template gives policy wording.
  3. Generate provenance on your most-deployed artefacts: container images and release binaries from one pipeline, using the build platform's native attestation rather than a script that writes its own claims.
  4. Verify in audit mode: add verification at the registry promotion step or admission controller in warn mode, and measure how many artefacts would fail.
  5. Enforce in rings: non-production first, then production namespaces by criticality. Keep a documented break-glass path (a time-boxed exception keyed to a digest, with an owner) and roll back by switching the policy to warn rather than deleting it.
  6. Extend to suppliers and dependencies: prefer registries that publish provenance, such as npm packages with provenance; see npm Trusted Publishing and Provenance.

Detection and measurement

  • Signing service logs: every signing request with requester, pipeline, artefact hash and approval; alert on signing outside release windows or from unexpected pipelines.
  • Transparency log monitoring: watch the certificate and Rekor logs for entries made with your identities that do not match a known build run.
  • Admission and promotion denials: track denials by reason (no attestation, wrong identity, unexpected parameters); a spike is either an attack or a broken pipeline, and both need attention.
  • Metrics: percentage of production artefacts with verified provenance at deploy; percentage of signing keys in hardware custody; number of active exceptions and their age; mean time to rotate a signing credential in exercises; share of release signatures with a valid timestamp.

Framework mapping

FrameworkReferenceCode signingArtefact attestation
NIST SP 800-53 Rev. 5CM-14 Signed Components; SI-7 and SI-7(15) Code AuthenticationPrimarySupporting (signed statements)
NIST SP 800-53 Rev. 5SR-4 Provenance; SR-11 Component AuthenticitySupportingPrimary
NIST CSF 2.0PR.PS-06 secure software development practices; GV.SC-05 supply chain requirements in contractsBothBoth
NIST SP 800-218 (SSDF v1.1)PS.2 release integrity verification; PS.3 archive and protect releases, including provenance dataPS.2PS.3
MITRE ATT&CK v20T1553.002, T1588.003, T1195.002, T1554; mitigation M1045T1553.002, T1588.003, M1045T1195.002, T1554

Common failure patterns

  • Treating a signature as proof of a clean build: SolarWinds showed that a signed update can carry a build-time implant.
  • Signing keys in CI variables: one leaked pipeline secret becomes the ability to sign as the company, as the HashiCorp exposure via Codecov showed.
  • Verifying existence, not content: an admission rule that accepts any attestation from any workflow in the organisation lets a test workflow attest a malicious image.
  • Wildcard identities: identity regular expressions that match every repository or branch erase the benefit of keyless pinning.
  • No log monitoring: keyless signing makes misuse visible only to those who look at the transparency logs.
  • Revocation as the only plan: expired or revoked certificates may still be honoured in some contexts, so plan application control and allow-list changes as part of response.

Practitioner checklist

  • Every public release is code signed with a hardware-held key and an RFC 3161 timestamp.
  • No signing key or long-lived signing token lives in CI variables or developer machines.
  • Release artefacts carry SLSA provenance generated by the build platform and bound to the digest.
  • Verifiers pin exact identities and issuers, and check source repository, buildType and externalParameters.
  • Deploy gates fail closed when provenance is missing, with time-boxed, owned exceptions.
  • Only release workflows on protected branches or tags can request signing or attestation.
  • Transparency logs are monitored for unexpected entries made with your identities.
  • A compromise runbook covers both a stolen key and a stolen CI identity, and has been exercised.

Standards and references

Related NHI Mgmt Group resources: Code Signing Security Guide, SLSA and Build Provenance Guide, Keyless vs Key-Based Code Signing, Sigstore Guide.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org