npm provenance and Sigstore
In 2023, npm added support for build provenance — cryptographic attestations that link a published package to the specific build run that produced it. This is a meaningful improvement to the npm security story. It's also limited in ways that matter.
What npm provenance is
When a package is published with provenance, npm records a signed attestation containing:
- The exact commit SHA of the source code the package was built from
- The build environment (GitHub Actions workflow, runner OS)
- The time of the build
The attestation is signed using Sigstore, a free public key infrastructure for signing software artifacts. The private key is generated ephemerally in the CI environment and signed by Sigstore's certificate authority (Fulcio), which binds the signing key to a GitHub Actions OIDC token. The signature is stored in Sigstore's public transparency log (Rekor).
On the npm registry page for a package with provenance, you can see: "Published from [repo]@[commit] via GitHub Actions." You can verify that the package tarball matches the build output from that exact commit.
What provenance prevents
Build environment tampering. If an attacker compromises a developer's machine and publishes a package from there — rather than from the expected GitHub Actions CI environment — the provenance attestation would be absent or would reference an unexpected build environment. This is a real attack vector: developers with publish rights who have their npm tokens stolen.
Tampered release artifacts. If a developer builds a package locally, manually modifies the tarball, and publishes the modified version, provenance verification would fail (the tarball hash wouldn't match the build output).
"Works on my machine" supply chain attacks. A developer who accidentally introduces malicious behavior in their local build environment — through a compromised tool, a compromised npm package in their dev dependencies — and publishes from there would produce a package with a provenance attestation that points to "local build" rather than a CI environment.
What provenance does NOT prevent
Malicious code in the source repository. If the source commit referenced by the provenance attestation contains malicious code, the provenance is valid — it correctly attests that the package was built from that commit. An attacker who gains write access to the source repository (through account takeover, a malicious commit merged via PR, etc.) can publish a package with valid provenance that contains malicious code.
Compromised build environments. If the GitHub Actions environment itself is compromised — through a malicious action, a compromised dependency in the build tools, or a compromised GitHub Actions runner — the provenance attestation would reference the legitimate workflow but the package would contain malicious code.
Most real-world supply chain attacks. The event-stream attack, the ua-parser-js attack, the litellm attack, the PyTorch attack — all of these involved legitimate maintainer accounts publishing from expected environments. Provenance attestations would have been present and valid for all of them.
The complementary role of Veln
npm provenance and Veln are designed to detect different threat classes. They work together:
| Threat | npm Provenance | Veln | |---|---|---| | Package built outside CI | Detects (provenance absent or references local) | Detects (publisher behavior change) | | Malicious code committed to source repo | Does not detect | Detects (AST diff, Veln Lens, canary sandbox) | | Compromised CI build environment | Does not detect | Detects (behavioral sandbox, Lens) | | Compromised maintainer account | Does not detect | Detects (publisher account signals, community consensus) | | Targeted attack (different binary per user) | Does not detect | Detects (consensus hash mismatch) | | CDN-level tarball tampering | Partially (hash in attestation) | Detects (community consensus) |
How to verify provenance
# Verify provenance for an installed package
npm audit signatures
# Check if a specific package has provenance
npm view <package-name> dist.attestations
Packages with provenance display a shield icon on the npm registry page. Packages without provenance are not necessarily unsafe — provenance is not yet universal — but provenance adds confidence when present.
npm provenance is a meaningful step forward. Veln covers the gaps it leaves open.