Manav.id
Standards ยท 17 min read

Sigstore proves the pipeline. Nothing proves the person.

Keyless signing and build provenance answer a hard question with real rigour: which build system produced this artifact, from which source, at which moment. They do not answer a different question that everyone downstream assumes has been answered. Did a human decide this should ship?

A release nobody decided to make

Picture a maintainer on a Tuesday morning, coffee going cold, scrolling an issue tracker. A notification says version 4.2.0 of their package has published. They did not cut it. They open the Actions tab and there it is: a workflow run, green, seven minutes long, triggered by a tag push. The tag was pushed with a personal access token that has been valid for fourteen months and lives in a place they stopped thinking about a year ago.

They check the artifact. It has provenance. The signature verifies. The transparency log has an entry with a timestamp. The certificate chains to a real identity: the workflow, in that repository, on that commit. Every downstream consumer who runs verification will get a green check, because everything the verification checks is true. The build really did happen in that repository. The workflow really did produce that artifact. The log entry really is there.

The maintainer sits there for a moment, holding a cold coffee, looking at a cryptographically flawless record of something they did not do.

This is not a criticism of the tooling. The tooling did its job exactly as designed and reported the truth. The gap is that the truth it reports is narrower than the sentence people read it as. Verification said this artifact came from that pipeline. Everyone downstream heard this artifact is what the maintainers intended to publish. Those are different claims, and only one of them was checked.

Does a Sigstore signature prove a human approved the release? No. Sigstore proves that a specific workload identity, usually a CI job in a specific repository on a specific commit, produced the artifact, and records it in a public transparency log. It says nothing about whether a person decided to ship. Proving that requires a separate attestation signed by a human on a device the pipeline cannot reach.

What did Sigstore and SLSA actually solve?

Start with credit, because it is owed and because the gap only makes sense once you understand the achievement precisely.

For twenty years, artifact signing was a good idea that almost nobody did. The reason was not ignorance. It was key management. Signing meant generating a long lived private key, storing it somewhere it would not leak but where you could still reach it at release time, rotating it on some schedule you would inevitably miss, distributing the public half to consumers who had no reliable way to know it was yours, and revoking it if it was ever exposed, through a process that mostly did not work. Every one of those steps was a place for a small project to give up, and small projects gave up in enormous numbers.

Keyless signing removed the reason people did not sign

Sigstore's central insight was that the long lived key was the problem, and that you could delete it. Instead of holding a key, a signer authenticates to an OpenID Connect provider, receives an identity token, and presents it to a certificate authority (Fulcio) that issues a certificate valid for a few minutes. You sign within that window. The private key never needs to be stored, because by the time anyone could steal it, it is worthless.

That leaves an obvious question: if the certificate expired ten minutes after issue, how does a consumer verify the signature next year? The answer is the transparency log (Rekor), which records the signing event with a timestamp. Verification becomes: this signature was made by this identity, during the window when its certificate was valid, and here is the public, append only, independently auditable record of that happening. The log is doing the job that certificate validity periods cannot do alone.

The analogy that gets this across: a long lived signing key is a rubber stamp in a drawer, and the whole problem of stamps is that drawers get opened. Keyless signing replaces the stamp with a notary who is only in the room for ninety seconds, and a public ledger recording every document notarised. You cannot steal the notary.

Workload identity made the signer specific

The second piece is what the certificate actually attests to. When a CI job signs, the OIDC identity is not a person's email address. It is the workload: this repository, this workflow file, this trigger, this commit. That is a genuinely useful thing to bind to, because it is checkable. A consumer can write a policy saying they will accept artifacts signed by a specific workflow in a specific repository and reject everything else, and that policy is meaningful in a way that "signed by someone with a key" never was.

SLSA sits alongside this as a framework rather than a tool, describing build integrity in levels: whether provenance exists, whether it is generated by the build platform rather than the user, whether the build is isolated from tampering by the person requesting it. Together with in-toto's attestation format, which gives a standard envelope for statements about artifacts, this is a serious body of work by serious people. Registry support followed: npm publishes provenance built on this machinery, and PyPI's trusted publishing uses OIDC to let a CI workflow publish without a long lived API token, which removes an entire category of credential theft.

The result is that a well configured modern release pipeline can prove, to a stranger, that a given artifact was built by a specific automated process from a specific commit. Fifteen years ago that was a research paper. Now it is a default in package managers used by millions of people. That is a large win and nothing below diminishes it.

What does the attestation actually say?

Read a provenance attestation as a sentence and you will find it is scrupulously honest about its own scope. It says, roughly: the builder identified as X produced the artifact with digest Y from the source at revision Z, beginning at time T1 and finishing at T2, with these parameters.

Notice what is not in that sentence. There is no subject who wanted this. There is no decision. There is no moment where a person weighed whether this change was ready for the people who depend on it. The attestation describes a process, faithfully and completely, and processes do not have intentions.

That is not a flaw in the design. It would be strange to expect a build system to attest to a state of mind. The flaw is in the reading. When a consumer sees a green verification result, the inference they draw is not "a computer did a thing correctly." It is "this is legitimate," and legitimacy is a claim about people.

Follow the trigger chain

Here is the analytical core of this post, and it is worth going slowly. A CI job does not run spontaneously. Something triggered it. Trace that chain backwards and see where the human actually sits.

A merge triggered it. Someone approved a pull request. That approval was a button click inside an authenticated browser session. If that session was stolen, and session theft is now an industrial business rather than a boutique one, the approval is the attacker's and the pipeline cannot tell. We have written about the mechanics of that theft separately in your MFA worked perfectly and the attacker was already inside the session. The build system sees a merge event. It cannot see whose hands were on the keyboard.

A tag push triggered it. Tags are pushed with credentials, and credentials leak. A personal access token in a stale environment file, a deploy key on a laptop that was sold, an SSH key copied to a second machine during a migration in 2023. The token is valid, so the push is valid, so the build is valid, so the provenance is valid. Nothing anywhere in that chain is lying.

A schedule triggered it. Nightly builds that promote to release on green. Here there is no human in the loop by design, which is a legitimate engineering choice, and it means the provenance describes a decision that no person made at any point.

An agent triggered it. This is the newest link and it is growing fastest. Coding agents open pull requests, respond to review comments, and in a rising number of repositories have permissions to merge and to tag. When an agent cuts a release, the provenance is perfect and the decision was made by a language model reasoning about an issue thread. We have written about the volume problem this creates for maintainers in maintainers are drowning and the review queue is the bottleneck nobody funds.

In every one of those four cases, verification passes. In three of the four, the person who would be held responsible for the release never formed an intention about it. The pipeline is not compromised in the ordinary sense. It is being used correctly by something that is not the maintainer.

ArtifactWhat it provesWhat it does not prove
Sigstore signatureA specific workload identity signed this digest, recorded in a public logThat any person authorised the signing
SLSA provenanceWhich builder, which source revision, which parameters, whenWhy the build was triggered, or by whom
Trusted publishingThe registry accepted a publish from a specific CI workflow, no long lived tokenThat a maintainer decided to publish this version
Signed git commitA key that lives on someone's machine signed this commit objectThat the key holder was present, or that the commit was meant to ship
Registry two factor authenticationA login satisfied a second factor at some pointAnything about a later publish that reused the session
Human release attestationAn enrolled person signed this exact digest as a release decision, at a stated timeThat the release is correct, tested, or wise

Why does this matter more in 2026 than it did in 2022?

Three things changed at once.

The first is that machine provenance became common. This sounds like progress, and it is, but it has a second order effect worth stating plainly: a valid signature now carries more weight with consumers than it used to, which means that anything which obtains a valid signature inherits that weight. Provenance raises the value of tricking the pipeline. The contrarian version of this argument is that widespread attestation makes supply chains more forgeable at the margin, not less, because it launders whatever the pipeline was persuaded to build. That is not an argument against provenance. It is an argument that the next layer has to be about people, because the machine layer is now well covered and attackers move to what is not.

The second is that pipeline resident attacks stopped being theoretical. The self replicating npm worm activity of 2025 and its later waves propagated through continuous integration workflows themselves, using the automation as the transport. We covered that campaign and the case for human signed publication in Sigstore signs the build, who signed the decision to publish, so this post will not restate it. The relevant point here is narrow: an attack that lives inside the workflow produces artifacts through the normal path, and the normal path is the one that generates the attestations.

The third is regulatory. The European Union's Cyber Resilience Act, Regulation (EU) 2024/2847, phases in obligations for products with digital elements across the second half of this decade, with vulnerability reporting duties arriving before the full application date. In the United States, Executive Order 14028 and the NIST Secure Software Development Framework pushed provenance and SBOMs into procurement language. None of these mandate a human release attestation. All of them create buyers who ask "how do you know this artifact is what you meant to ship," and who are no longer satisfied with "we use CI."

How would a human release attestation compose with what exists?

The design principle that matters here: this should be an additional predicate, not a replacement, and it should be verifiable by exactly the tooling people already run. Anything that requires abandoning Sigstore is both wrong and dead on arrival.

in-toto already provides the envelope. An attestation is a statement about a subject, identified by digest, with a predicate type that says what kind of claim is being made and a predicate body carrying the claim. Build provenance is one predicate type. A human release decision can be another, sitting beside it, about the same subject.

The predicate shape

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    {
      "name": "pkg:npm/[email protected]",
      "digest": { "sha512": "9f2c4e1a7b03d5..." }
    }
  ],
  "predicateType": "https://manav.id/attestations/human-release/v1",
  "predicate": {
    "decision": "release",
    "signer": {
      "keyId": "ed25519:8c1d5f30a94b...",
      "enrolledAt": "2026-02-11T09:14:22Z"
    },
    "signedAt": "2026-09-23T16:41:07Z",
    "payloadHash": "sha256:1a7b9c02e4...",
    "assurance": "device-bound",
    "receiptUrl": "https://manav.id/r/9QK2XVn7"
  }
}

Read it the way we read the provenance attestation. This one says: the holder of this enrolled key signed a statement whose hash is this, asserting a release decision about this exact digest, at this time. It is as narrow and as honest as the build attestation. It does not claim the release is good. It claims a specific person decided it.

The payloadHash field is the part engineers should look at hardest, because it is where the security actually lives. The signature is not over a vague assertion of approval. It is over a canonical serialisation of the decision, including the artifact digest. Sign a hash of "I approve," and an attacker who controls the display can show you one thing and have you sign another. Sign a hash that includes the digest of the exact bytes being released, and the substitution attack disappears, because a different artifact produces a different hash and therefore a different signature. This is the same discipline that keeps a payment authorisation honest, and we go through it in detail in the signers signed what the screen showed and the screen was lying.

The policy: require both, scoped by blast radius

The most useful thing in this post is not the predicate. It is the policy, because the policy is where a security team makes a judgment about cost.

# verification policy, expressed as pseudocode
verify(artifact):
    require provenance where
        builder     == "https://github.com/acme/widgets/.github/workflows/release.yml"
        sourceUri   == "git+https://github.com/acme/widgets"
        buildType   in TRUSTED_BUILD_TYPES

    if artifact.dependentCount > 10_000 or artifact.tier == "critical":
        require human-release where
            signer.keyId in MAINTAINERS[artifact.package]
            subject.digest == provenance.subject.digest
            abs(signedAt - provenance.buildFinishedOn) < 24h
            assurance   == "device-bound"

    accept

Three details in that policy are doing real work. The digest equality check binds the human decision to the same bytes the builder produced, so an attacker cannot pair a genuine human attestation for version 4.1.9 with a malicious artifact. The time window stops a signature harvested months earlier from being replayed against a new build. And the tier condition is the honest part: this is not applied to everything, because applying it to everything is the wrong answer.

What the maintainer experiences

The workflow pauses at the release step. A notification arrives on the maintainer's phone showing the package name, the version, and a short digest. They read it, and they either approve or they do not. It takes about fifteen seconds and it happens once per release, not once per commit.

The important property is where the signing happens. It is on a device that the pipeline cannot reach, which is the whole point. A worm inside the runner can do everything the runner can do, and the runner cannot produce a signature from a key it has never held. This is the same separation of domains that makes companion device confirmation useful in payments, applied to release engineering.

What are the honest limits?

This audience will supply these objections whether or not the post does, so here they are first, and the strongest one goes first.

A trusted maintainer who ships a backdoor signs it perfectly. The most sophisticated supply chain attack of recent years worked by patiently gaining maintainer trust over a long period and then using legitimate access. A human release attestation would have been produced, correctly, by the person who had every right to produce it, and it would have been true. This control does not address the malicious insider, and any claim that it does is false. What it changes is that the record names a person, which matters for detection and for accountability afterwards, and which is not nothing, but it is emphatically not prevention.

A human who taps without reading adds a name and no assurance. This is real and it gets worse with frequency. A maintainer prompted forty times a day becomes a rubber stamp within a week. This is the argument for scoping by blast radius rather than requiring it everywhere, and it is why the policy above has a tier condition rather than applying universally.

Fully automated release is often the better practice. Continuous delivery with strong tests, staged rollout, and fast rollback is a genuinely superior model for a great many projects, and inserting a human is a step backwards for them. A human gate makes sense where the action is hard to reverse and the blast radius is wide, which describes publishing to a public registry with many dependents, and does not describe an internal service deploying forty times a day.

A compromised maintainer device defeats it. Separation of domains raises the cost of attack. It does not create a domain that cannot be compromised.

Adoption is the entire problem. A predicate nobody produces and no registry displays is a specification, not a control. This needs registries to surface it, consumers to require it, and maintainers to enroll, and that ordering problem is genuinely hard. Manav has shipped the signing and offline verifiable receipts, documented in the developer docs, and the signed code demo shows the shape, but registry and CI integrations are not built. Treat everything in this post about npm, PyPI or crates.io as a proposal rather than a product.

Pseudonymity must survive. A great deal of important open source is maintained by people who do not publish their legal identity, for reasons ranging from ordinary privacy to physical safety. Any human layer here must bind to a key, not to a name. The attestation above carries a key identifier and no personal data, and that is deliberate.

What to do this week

  1. Enumerate every credential that can trigger a release in your repositories: personal access tokens, deploy keys, CI secrets, registry tokens. Write down when each was created and who created it. The stale ones are the story.
  2. List which of your releases can be cut with no human action at all. For most teams this number is higher than they expect and nobody has ever counted it.
  3. Check whether agents have write or merge permissions in your repositories, and whether that includes tag creation.
  4. Verify your own provenance as a stranger would. Run the verification a consumer runs and read the output as a sentence. Ask what it actually asserts.
  5. Pick your tier one packages by dependent count rather than by how important they feel internally. Blast radius is the only ranking that matters here.
  6. Write down the release approval you would want in an incident report six months from now, then compare it to what your logs would actually produce.
  7. If you maintain something widely consumed, decide now which versions warrant a human step, before an incident decides for you.

Frequently asked questions

Does a Sigstore signature prove a human approved the release? No. It proves that a workload identity, typically a CI job in a named repository at a named commit, produced and signed the artifact, and that the event is recorded in a public transparency log. Whether a person decided to ship is a separate claim that requires a separate attestation, signed by a human on a device the pipeline does not control.

Is this a criticism of Sigstore or SLSA? No. Both solve a hard problem well and their scope is stated accurately in their own documentation. The gap described here is in how downstream consumers read a green verification result, not in what the tools claim. The proposal composes with them as an additional in-toto predicate, and requires no change to existing signing.

Would this have stopped the xz-utils backdoor? No, and it is important to say so. That attack ran through a maintainer who had legitimately earned commit rights over a long period. They would have produced a valid human release attestation because they were the legitimate releaser. This control addresses compromised pipelines and stolen credentials, not patient insider abuse.

Does not signed git commits already bind a human? Partially. A signed commit proves a key signed a commit object, and that key usually lives on a developer machine where malware can reach it. It also proves nothing about the decision to release, since most commits are never released and releases often bundle many commits. It is a useful control at a different point in the chain.

Would this slow down releases? For patch releases cut many times a day, yes, which is why the policy should be scoped by blast radius rather than applied universally. A package with ten thousand dependents warrants fifteen seconds of human attention per release. An internal service deploying continuously does not.

Can maintainers stay pseudonymous? Yes, and any design that cannot is unusable in open source. The attestation binds a public key identifier, not a legal name. Manav stores a one way key rather than an identity, so a maintainer can be provably the same person across releases without being identifiable.

Who would standardise the predicate? The natural home is the in-toto attestation ecosystem and the OpenSSF community that maintains much of this work. Standardisation would be a good outcome, not a threat, because the value is in whether registries display the attestation and consumers require it, rather than in owning the format.

Sources

  1. Sigstore project documentation, on keyless signing, Fulcio certificate issuance and the Rekor transparency log: docs.sigstore.dev
  2. SLSA, Supply chain Levels for Software Artifacts, build levels and provenance requirements: slsa.dev
  3. in-toto attestation framework, statement and predicate structure: github.com/in-toto/attestation
  4. npm provenance documentation, on publishing with build provenance: docs.npmjs.com
  5. PyPI trusted publishing, on OIDC based publishing without long lived tokens: docs.pypi.org/trusted-publishers
  6. Regulation (EU) 2024/2847, the Cyber Resilience Act, on obligations for products with digital elements: EUR-Lex
  7. NIST Secure Software Development Framework, SP 800-218: csrc.nist.gov/projects/ssdf
  8. Executive Order 14028 on Improving the Nation's Cybersecurity: Federal Register
  9. OpenSSF, on open source supply chain security work and community projects: openssf.org
Provenance tells you which machine built the artifact. It was never designed to tell you which person meant to ship it, and we have been reading it as though it were.