Verifying npm Package Provenance Before You Depend on It
You want assurance that a dependency's published tarball actually came from its claimed source repository and CI, not a hijacked account. This page shows how to check npm provenance attestations before trusting a package.
Exact symptoms and error messages
# a package with no provenance gives you no build-origin guarantee
$ npm view some-lib dist.attestations
undefined
Root cause analysis
Provenance is a signed attestation, generated by CI via OIDC, that ties a published tarball to a specific source commit and build. A package without it offers no cryptographic link between the code on GitHub and the tarball on the registry, so an account compromise can publish anything. Verifying provenance is the consumer side of the publisher defenses in Supply-Chain Security Hardening and Adding SLSA Provenance to Package Releases.
Provenance is a signed attestation generated by CI via OIDC that binds a published tarball to a specific source commit and build workflow. Without it, there is no cryptographic link between the code you can read on GitHub and the tarball the registry serves — so a compromised maintainer account, or a registry-side tampering, can publish anything under a trusted name and you have no way to detect it. Verifying provenance is how a consumer regains that link.
What provenance does not prove is that the code is benign. It confirms origin and integrity — this tarball really came from that source and build, unmodified — not intent. A malicious-but-authentic author can still publish signed, provenance-backed malware. Provenance defends against account hijacks and supply-chain tampering, which is a large and important class of attack, but it is one layer among several rather than a guarantee of safety.
Provenance is a signed attestation, generated by CI via OIDC, that binds a published tarball to a specific source commit and build workflow. A package without it offers no cryptographic link between the code you can read on its source host and the tarball the registry serves, so a compromised maintainer account or registry-side tampering can publish anything under a trusted name and you have no way to detect it. Verifying provenance is how a consumer regains that link and gains assurance about where a package actually came from.
What provenance does not prove is that the code is benign. It confirms origin and integrity — this tarball really came from that source and build, unmodified — not intent, so a malicious-but-authentic author can still publish signed, provenance-backed malware. Provenance therefore defends against a specific and important class of attack: account hijacks and supply-chain tampering. It is one layer of a broader posture rather than a guarantee of safety, which is why it is paired with audit thresholds, host allow-listing, and script blocking.
Resolution and configuration patch
Check for and verify attestations before adopting a dependency:
# Does the package publish provenance?
npm view some-lib dist.attestations
# Verify the signed attestations for what you have installed
npm audit signatures
Prefer dependencies that publish provenance, and treat a missing attestation on a security-critical package as a reason to pin and review.
Check for and verify attestations before depending on a package, and enforce verification in CI:
# Does the package publish provenance?
npm view some-lib dist.attestations
# Verify signatures and provenance across the installed tree
npm audit signatures
Running npm audit signatures in CI fails the build when a package that should carry provenance does not verify, turning verification into an enforced gate rather than a manual spot-check. Prefer dependencies that publish provenance for security-critical code, and treat a missing attestation on such a package as a reason to pin the version and review before adopting.
CLI validation and debug commands
# Verify signatures/attestations across the installed tree
npm audit signatures
# Inspect the provenance's source repo and commit
npm view some-lib --json | jq '.dist.attestations'
Prevention and CI guardrails
- Prefer dependencies that publish provenance for security-critical code.
- Run
npm audit signaturesin CI to verify attestations on install. - Pin and review packages that lack provenance before depending on them.
- Publish provenance for your own packages so consumers can verify you in turn.
- Prefer dependencies that publish provenance for security-critical code.
- Run
npm audit signaturesin CI to verify attestations on every install. - Pin and review packages that lack provenance before depending on them.
- Publish provenance for your own packages so consumers can verify you in turn.
Verifying attestations across your dependency tree
Checking one package by hand does not scale; the practical move is to verify signatures and attestations across everything you have installed, as a CI step. npm audit signatures walks the installed tree and verifies registry signatures and provenance attestations, failing when verification does not hold.
# Verify registry signatures and provenance for the whole tree
npm audit signatures
Run it in CI so a package that loses its expected signature — or whose attestation does not verify — fails the build rather than shipping silently. For security-critical dependencies specifically, prefer ones that publish provenance, and treat a missing attestation on such a package as a reason to pin the version and review before adopting. The goal is to make provenance verification a routine gate, not a manual spot-check you do once and forget.
Publishing your own provenance
Verification has a mirror obligation: publish provenance for your own packages so your consumers can verify you in turn. With OIDC-based publishing from CI, the registry attaches an attestation tying your tarball to its source and build, and consumers running npm audit signatures see it verified.
permissions:
id-token: write
steps:
- run: npm publish --provenance
Granting the workflow id-token: write and publishing with --provenance is usually the whole change — and it doubles as the token-free publishing path, since the OIDC identity replaces a standing token. Publishing provenance is how you participate in the same chain of trust you rely on when consuming: you verify your dependencies, and you give your consumers the means to verify you, which is what makes the ecosystem-wide guarantee actually hold.
Verifying provenance across the whole tree
Checking one package by hand does not scale, so the practical approach is to verify signatures and attestations across everything installed, as a CI step. npm audit signatures walks the installed dependency tree and verifies registry signatures and provenance attestations, failing when a package that should carry provenance does not verify or when a signature does not match. Running it in CI turns provenance from a badge nobody checks into an enforced property: a dependency that loses its expected signature, or whose attestation does not match its claimed source, fails the build rather than shipping silently.
For security-critical dependencies specifically, the verification is worth pairing with a policy of preferring packages that publish provenance and treating a missing attestation as a signal to pin and review. Provenance coverage across the ecosystem is growing, so a security-important package that does not publish it is increasingly an outlier worth scrutinizing. Making npm audit signatures a routine gate, rather than a one-time manual check, is what keeps the assurance current as your dependency tree changes — every new or updated dependency is verified on the next CI run, so a package that quietly loses its provenance or fails verification is caught immediately.
Publishing your own provenance to complete the chain
Verification has a mirror obligation: publishing provenance for your own packages so your consumers can verify you in turn. With OIDC-based publishing from CI, the registry attaches an attestation tying your tarball to its source and build, and consumers running npm audit signatures see it verified. Granting the workflow id-token: write and publishing with --provenance is usually the entire change, and it doubles as the token-free publishing path since the OIDC identity replaces a standing token.
Participating in the chain of trust as both a consumer and a publisher is what makes the ecosystem-wide guarantee actually hold. You verify your dependencies' provenance, and you give your consumers the means to verify yours; the more packages that do both, the harder it becomes for a hijacked account or a tampered publish to go undetected anywhere in the graph. Provenance is not a feature you adopt purely for your own protection — it is a contribution to a shared verification fabric, and publishing it is the natural counterpart to relying on it when you install.
Where provenance fits in a layered defense
Provenance verification is one control in a layered supply-chain defense, and understanding what each layer covers clarifies why no single one suffices. Blocking install scripts stops arbitrary install-time code execution; an audit threshold catches known-vulnerable versions; host allow-listing with lockfile-lint blocks resolution from an untrusted registry; and provenance verification confirms a package came from its claimed source and build. Each addresses a distinct attack surface, so a package could pass three checks and fail the fourth — audited-clean but tampered, or script-free but from a malicious host.
Stacking them means an attacker must defeat every layer rather than any single one. A CI security gate that runs a frozen install with ignored scripts, a thresholded audit, a host allow-list check, and npm audit signatures for provenance measures every push against the whole posture, and each check is fast and deterministic. Provenance's specific contribution is the origin dimension: it is the layer that catches a hijacked account or a tampered publish, which the vulnerability, host, and script checks do not address. Placing it alongside the others — rather than treating any one as sufficient — is what turns a collection of individual controls into genuine defense in depth for the dependency graph.
Frequently Asked Questions
Does provenance prove the code is safe?
No — it proves the tarball came from the claimed source and CI build, not that the code is benign. It defends against account hijacks and tampering, not against a malicious-but-authentic author.
How do I verify provenance in CI?
Run npm audit signatures, which verifies registry signatures and provenance attestations for your installed packages, and fail the job if verification fails on a package you require.
Does provenance prove a package is safe?
No — it proves the tarball came from the claimed source and build, unmodified. It defends against account hijacks and tampering, not against a malicious-but-authentic author. Treat it as one layer of defense, not a safety guarantee.
How do I verify provenance across all my dependencies?
Run npm audit signatures in CI. It walks the installed tree and verifies registry signatures and provenance attestations, failing the build when verification does not hold — a routine gate rather than a manual spot-check.
How do I publish provenance for my own package?
Publish from CI with id-token: write permission and npm publish --provenance. The registry attaches an attestation tying the tarball to its source and build, which also removes the need for a standing publish token.
Does provenance prove a package is safe?
No — it proves the tarball came from the claimed source and build, unmodified. It defends against account hijacks and tampering, not against a malicious-but-authentic author. Treat it as one layer of a supply-chain posture alongside audit thresholds, host allow-listing, and script blocking.
How do I verify provenance across all my dependencies?
Run npm audit signatures in CI. It walks the installed tree and verifies registry signatures and provenance attestations, failing the build when a package that should carry provenance does not verify — a routine, enforced gate rather than a manual spot-check.
How do I publish provenance for my own package?
Publish from CI with id-token: write permission and npm publish --provenance. The registry attaches an attestation tying the tarball to its source and build, which also removes the need for a standing publish token.
Where does provenance fit alongside my other supply-chain checks?
It is the origin layer. Script blocking covers install-time code, an audit threshold covers known vulnerabilities, lockfile-lint covers resolution hosts, and provenance covers where the package came from — catching a hijacked account or tampered publish the others miss. Run all four in one CI gate for defense in depth.
Do all npm packages publish provenance?
Not yet — coverage is growing but far from universal. For security-critical dependencies, prefer ones that publish provenance and treat a missing attestation as a reason to pin and review, while running npm audit signatures to verify the ones that do.
Related
- Supply-Chain Security Hardening — the broader supply-chain defenses this control is part of.