Updated 23 August 2026 — this article was rewritten with primary sources added and unsupported claims removed.
When crates.io began linking a published crate back to the CI run that built it, the feature was widely read as an answer to Rust’s supply-chain problem. It answers a narrower question than that, and the difference is the whole point. A provenance link tells you where an artefact came from. It tells you nothing about what is inside it.
What Trusted Publishing replaces
Until recently, publishing a crate from CI meant putting a long-lived crates.io API token into GitHub Actions secrets. That token was a standing credential: it did not expire, it was as powerful as your account, and anyone who extracted it could publish under your name indefinitely. Token theft, not malicious code review failures, is how a large share of registry compromises actually begin.
Trusted Publishing removes the token. As the Rust team described it, the feature “eliminates the need for GitHub Actions secrets when publishing crates from your CI/CD pipeline” — instead you nominate a GitHub repository on crates.io, and that repository requests a short-lived token over OpenID Connect at publish time (Rust Blog). The credential now lives for the length of one workflow run and is bound to one repository. Steal it an hour later and it is worthless.
The design is not original to Rust, and the team says so plainly: it follows RFC 3691 and credits the PyPI team’s earlier work. That borrowing matters, because it means the same mental model now applies across most of the ecosystems a working developer touches.
What the build link proves — and what it does not
Because the publish is tied to an OIDC identity, the registry can record which repository and which workflow run produced the artefact, and show it on the crate page. That is a real gain. It converts this crate claims to come from that GitHub project into something a machine can check.
What it does not do is inspect the code. A provenance attestation binds an artefact to a build; it says nothing about whether the build’s inputs were trustworthy. If an attacker lands a malicious commit in the repository — through a compromised maintainer account, a poisoned dependency of the build itself, or a pull request nobody read closely — the resulting crate is published with a perfect, verifiable provenance record. The chain of custody is intact. The cargo is not.
GitHub’s own description of npm provenance is careful about this, framing it as “publicly providing a link to a package’s source code and build instructions from the build environment” (GitHub Blog). A link to source and build instructions is exactly what it says: an audit trail, not an audit.
How five registries answer the same question
The ecosystems have converged on two distinct mechanisms, and it is worth being clear about which problem each solves.
| Registry | Mechanism | What it actually proves | Primary source |
|---|---|---|---|
| crates.io (Rust) | Trusted Publishing via OIDC; publish linked to the GitHub Actions run | Which repo and workflow produced this version, without a standing token | Rust Blog |
| npm | Trusted publishing plus automatic SLSA provenance attestations | Build origin, signed and publicly verifiable | npm Docs |
| PyPI | Trusted Publishers plus Sigstore-backed digital attestations | Build origin, with signatures anchored in a public transparency log | PyPI Blog |
| RubyGems | Trusted publishing via OIDC | Build origin, without long-lived API keys in CI | RubyGems Guides |
| Go modules | Checksum database — a Merkle-tree transparency log at sum.golang.org | That the bytes you fetched are the bytes everyone else fetched | The Go Blog |
Go is the odd one out, and instructively so. Its checksum database does not care where a module was built. It guarantees immutability: once a version’s hash is in the log, nobody — including the author, including Google — can quietly swap the contents later without every client noticing. Trusted Publishing guarantees origin. They are complementary, and neither substitutes for the other.
How the handshake actually works
The mechanism is worth understanding, because it explains why the credential cannot be stolen in the usual way. When a workflow runs, GitHub mints a short-lived JSON Web Token describing that specific run: which repository, which branch or tag, which workflow file, which environment. That token is signed by GitHub and is meaningless anywhere else.
The publish step presents it to crates.io. The registry verifies the signature against GitHub’s published keys, checks that the repository named inside matches one the crate owner has explicitly nominated, and only then issues an API token — one scoped to that crate and valid for minutes. Nothing durable is stored in the repository at any point. An attacker who dumps your Actions secrets finds nothing to steal, because there is nothing there.
The trust has moved rather than disappeared. You are now trusting GitHub’s identity provider and your own repository settings: who can push to the nominated branch, who can approve a workflow, whether a compromised Action in your pipeline could hijack the publish step. Those are better things to have to defend than a token in an environment variable, but they are not nothing, and branch protection on the publishing branch stops being optional once the branch is what authorises releases.
What adopting it involves
Adoption is deliberately not fully automatic. The Rust team notes that you must publish your first release manually before you can configure Trusted Publishing — the crate has to exist, with an owner, before a repository can be nominated to publish it. After that the repository is named on the crate’s settings page and the token disappears from CI.
One current limit is worth planning around: crates.io’s implementation supports GitHub Actions only at present, though the Rust team states it was built so other providers such as GitLab CI can be added later. Projects publishing from elsewhere keep using API tokens for now, which makes token scope and rotation still worth attention rather than a solved problem.
That distinction is not academic. The xz backdoor was published with an intact chain of custody and a maintainer whose trust had been earned over years — provenance would have recorded the build faithfully and told you nothing. The same reasoning applies to any downloaded artefact, including machine-learning model files, some formats of which execute code when loaded, and to closed-source tools whose behaviour no customer can audit.
The gap nobody has closed
There is a third property none of these mechanisms deliver: that the artefact you install corresponds to the source you can read. For crates specifically, the published tarball is uploaded by the build, not reconstructed from the repository, so verifying that the two match is a separate exercise. PyPI’s attestation work is explicit that attestations are about signing the distribution, and directs maintainers to its attestations documentation for what the signature covers.
Closing that gap requires reproducible builds — the ability to rebuild the artefact from source and get a byte-identical result. That work is ongoing across every ecosystem in the table and finished in none of them.
So the honest summary for a Rust developer is this. Trusted Publishing has removed one of the most-exploited weaknesses in the publishing chain, and it costs nothing to adopt. It has not made a crate’s contents trustworthy, and a provenance badge is not a review. The useful habit is to read the link rather than the badge: check that the repository named is the one you think you are depending on, and that the code in it is code you would accept.