An npm provenance statement is a cryptographically signed attestation that links a published package version to the exact source commit and CI workflow that built it — it proves where and how a package was built, not that the code inside it is safe. That distinction matters because provenance is increasingly treated as a trust badge on npmjs.com, and a green checkmark is doing a lot of load-bearing work in people's heads that the underlying math never promised.
How a provenance statement gets made
When you run npm publish --provenance from a supported CI system (GitHub Actions or GitLab CI, as of early 2026), the following happens:
- The CI runner requests a short-lived OIDC token from its identity provider. The token encodes the repository, the workflow file path, the commit SHA, and the trigger ref.
- npm's tooling sends that identity to Fulcio, Sigstore's certificate authority, which issues an ephemeral signing certificate valid for about 10 minutes.
- A SLSA v1 provenance document is generated, signed, and the signature is logged in Rekor, Sigstore's public transparency log.
- The registry stores the attestation and serves it from
https://registry.npmjs.org/-/npm/v1/attestations/<pkg>@<version>.
No long-lived keys exist anywhere in this flow. That's the clever part: there's no key for a maintainer to leak, because the signing identity is the CI job.
Verification on the consumer side is one command:
npm audit signatures
This checks both registry signatures and provenance attestations for everything in your package-lock.json, and exits non-zero on mismatch. It's cheap — a few seconds on a lockfile with 1,200 entries — and belongs in CI next to npm ci.
What it actually proves
A valid provenance statement gives you four concrete facts:
| Claim | Verified by |
|---|---|
Built from repo github.com/org/pkg | OIDC token subject, recorded in the Fulcio cert |
Built from commit a1b2c3d | resolvedDependencies digest in the SLSA predicate |
Built by workflow .github/workflows/release.yml | Cert extension build-config-uri |
| Published tarball matches what CI produced | SHA-512 subject digest in the attestation |
That last row is the practical win. It kills the classic laptop-publish attack, where a compromised maintainer machine ships a tarball that never appeared in any repo. The event-stream incident in 2018 involved code that existed only in the published artifact; provenance makes that class of divergence detectable by anyone, not just forensics teams after the fact. If you want the history, we covered it in the event-stream backdoor incident.
It also gets you to SLSA Build Level 2, and — with GitHub's hardened runners and reusable workflows — arguably Level 3 for the build isolation requirement.
What it does not prove
Here's the boundary, stated bluntly:
- It does not prove the source code is benign. If a malicious commit lands in the repo, provenance will happily and accurately attest that the malware was built from that commit. The xz-utils backdoor sat in the source tree; provenance would have attested it perfectly.
- It does not prove the maintainer account is uncompromised. An attacker who takes over a GitHub account can push a commit, trigger the release workflow, and mint flawless provenance. The ua-parser-js hijack in 2021 would look more legitimate with provenance, not less.
- It does not prove dependency safety. The attestation covers one package's build. Its 40 transitive dependencies are out of scope entirely.
- It does not prove the workflow itself was trustworthy. A release workflow that runs
curl | bashfrom an attacker-controlled URL still produces valid provenance.
Adoption also limits what you can enforce. Roughly one in five of the top 500 npm packages published attestations by late 2025, and the long tail is far lower. A policy of "reject anything without provenance" fails your build today; a policy of "alert when a package that had provenance suddenly publishes without it" is enforceable and catches something real — a publish path change is a legitimate threat signal.
Trusted publishing changes the account-takeover math slightly
npm's trusted publishing (generally available since mid-2025) lets you bind a package to a specific repo and workflow, so publishes are only accepted via that OIDC identity — no npm tokens at all. Combined with provenance, this means an attacker now needs write access to the repository and the ability to pass branch protection, rather than just a leaked NPM_TOKEN in a .npmrc or CI secret. It narrows the attack surface; it doesn't close it. Repo write access via a phished maintainer still wins.
Configuration is in the package settings on npmjs.com, and once enabled you should revoke every legacy automation token:
npm token list
npm token revoke <id>
Where provenance fits in a real pipeline
Treat provenance as one signal in a chain, not a verdict:
npm ciagainst a committed lockfile — pins the resolution.npm audit signatures— verifies registry signatures and attestations.- SCA scanning for known CVEs and malicious-package intel — this is the layer that actually inspects what the code does, which provenance never claims to. A software composition analysis pass catches the malicious-by-construction packages that carry perfectly valid attestations.
- SBOM capture at build time, so you can answer "did we ever ship this version" six months later. Tooling like SBOM Studio can diff attestation coverage across releases, which is how you spot the publish-path regressions mentioned above.
The dry summary: provenance moves npm from "trust the tarball" to "trust the repo and its CI." That's real progress. It just relocates the problem rather than solving it, and the repos are where attackers went next.
Frequently asked questions
Does npm provenance prevent typosquatting?
No. A typosquatted package can be published from its own repository with completely valid provenance — the attestation would truthfully say evil-lodash was built from github.com/attacker/evil-lodash. Provenance authenticates the build path, not the package's legitimacy or name.
Can I require provenance for all dependencies?
Not practically in 2026. Coverage across the registry is too thin, so a hard gate blocks most installs. The enforceable policy is monitoring for regressions: packages that previously shipped attestations and then stopped, which often indicates a changed (possibly compromised) publish path.
Is provenance the same as package signing?
They overlap but differ. npm also signs all packages with a registry-held key, which proves the registry served you the bytes it has. Provenance is stronger: it's signed evidence from the build system itself, linking the artifact to source and workflow via Sigstore's Fulcio and Rekor infrastructure.
Would provenance have stopped the xz-utils backdoor?
No, and it's a useful calibration exercise. The xz backdoor was committed to the source repository by a trusted-looking maintainer; a provenance statement would have accurately attested a malicious build. Detection layers that analyze behavior and maintainer risk — the approach platforms like Safeguard take alongside attestation checks — address that gap, not provenance alone.