Using sigstore and cosign to Verify npm Packages Have Not Been Tampered With

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
sigstore solves the core problem of software supply chain verification: proving that a package you are about to install was built from a specific source commit by a specific identity, and has not been modified since. The TanStack attack succeeded in part because nothing at the install step alerted developers that the package they were installing was not the one the TanStack team built. npm provenance, built on sigstore, would have surfaced that discrepancy. This guide covers the practical setup: signing your own packages during CI, verifying packages you consume, and what verification failure means in practice.
How sigstore Works Without Long-Lived Keys
Traditional code signing requires a signing key that must be stored securely, rotated periodically, and revoked if compromised. Stolen signing keys are a major attack vector, a stolen key lets an attacker sign arbitrary packages as a legitimate maintainer.
sigstore eliminates the long-lived key problem with a keyless signing model:
- The developer (or CI system) authenticates via OIDC, in a GitHub Actions context, this is the same OIDC token used for cloud provider authentication.
- Fulcio (sigstore's certificate authority) issues a short-lived X.509 signing certificate that expires in 10 minutes, bound to the OIDC identity (e.g., the GitHub Actions workflow URL).
- The package is signed with this ephemeral certificate.
- The signature and a certificate verification bundle are recorded in Rekor, sigstore's append-only transparency log.
- At verification time, anyone can retrieve the certificate and signature from Rekor and verify that the package was signed by the claimed identity during the claimed build.
The result: there is no long-lived key for an attacker to steal. A malicious actor who compromises the package registry cannot retroactively create a valid sigstore signature for a tampered package, they would need to also compromise the OIDC identity at the time of publication.
Step 1: Enable npm Provenance When Publishing
npm's provenance feature, released in 2023, is sigstore integration built into the npm CLI. When you publish with --provenance from a GitHub Actions workflow, npm automatically:
- Requests a sigstore certificate for your workflow's OIDC identity
- Signs the package tarball
- Records the signature in Rekor
- Attaches the provenance statement to your package on the registry
To enable it, add --provenance to your publish command in your GitHub Actions workflow:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for sigstore OIDC
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
After publishing, your package page on npmjs.com shows a provenance badge linking to the Rekor entry and the specific GitHub Actions run that built the package.
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Step 2: Verify Provenance of Packages You Consume
Verifying provenance before installing a package confirms it was built from the claimed repository by an authenticated CI system.
Using npm audit signatures:
npm audit signatures
This command verifies the registry signatures for all packages in your current node_modules. It does not verify provenance (build source), but it confirms the packages match what the registry served, detecting a man-in-the-middle or a registry compromise.
Checking provenance for a specific package:
npm view @tanstack/react-router --json | jq '.dist.attestations'
This returns the attestation metadata including the Rekor log ID and the GitHub Actions workflow that built the package. Cross-reference the workflow URL against the official TanStack repository.
Using the sigstore CLI for deeper verification:
# Install cosign
brew install cosign
# Verify an npm package's provenance
cosign verify-npm-provenance @tanstack/react-router@1.120.0
This verifies the OIDC identity that signed the package matches the expected GitHub repository and workflow path.
Step 3: Add Verification to Your CI Pipeline
Verification in developer workflows is valuable, but verification in CI, before a build uses a dependency, catches tampered packages before they reach any developer machine.
Add this step to your CI workflow after npm ci:
- name: Verify npm package provenance
run: |
# Verify signatures for all installed packages
npm audit signatures
# For critical dependencies, verify provenance explicitly
PACKAGES="@tanstack/react-router react react-dom"
for pkg in $PACKAGES; do
version=$(node -e "console.log(require('./node_modules/$pkg/package.json').version)")
echo "Verifying $pkg@$version"
npm view "$pkg@$version" --json | jq -e '.dist.attestations // error("No provenance")' || \
echo "WARNING: $pkg has no provenance attestation"
done
This approach fails fast if any critical dependency lacks provenance or has an invalid signature. Over time, as more packages adopt provenance, you can convert warnings to hard failures.
Step 4: Sign and Verify Container Images with cosign
If your Node.js application ships as a Docker image, cosign extends the same verification model to container images.
Signing an image after build in GitHub Actions:
- name: Sign container image
run: |
cosign sign --yes \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
env:
COSIGN_EXPERIMENTAL: '1'
Verifying before deployment:
cosign verify \
--certificate-identity-regexp 'https://github.com/yourorg/yourrepo/.github/workflows/.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
your-registry/your-image:tag
This confirms the image was built by your GitHub Actions workflow and not modified after push. In a Kubernetes environment, integrate this with Kyverno or OPA policies that reject pods using images without a valid cosign signature.
What Verification Failure Means and What to Do
npm audit signatures failure means one of:
- The package was modified after being published to the registry (tampering)
- The package was published to a mirror registry and the signature does not match
- The npm registry served a different version than the one you requested
For a package with no provenance attestation, it means the package was published without provenance, which describes most packages today. Treat the absence of provenance as a risk factor, not an automatic failure, until your critical dependencies all have provenance.
For a provenance mismatch, where the provenance exists but points to a different repository or workflow than expected, treat it as a security incident. Remove the package from your node_modules immediately, audit your lockfile for the commit that introduced it, and check whether your CI ran with the tampered package already installed.
The bottom line
sigstore provenance does not prevent supply chain attacks, it makes them detectable. A tampered package published without a valid provenance signature fails verification at install time. The investment is adding two lines to your publish workflow and one command to your CI pipeline. Given that the TanStack attack would have been caught at install time with provenance enabled, the risk-reduction-to-effort ratio is as high as any security control available to a Node.js team.
Frequently asked questions
Does sigstore provenance work for private npm packages?
Yes. npm provenance works with private registries and scoped packages. The provenance statement links to the specific GitHub Actions run regardless of whether the package is public or private. The Rekor transparency log entry is public by default, which means the build metadata is public even for private packages, consider this if you need build pipeline confidentiality.
What happens if I publish a package without --provenance?
The package is published normally without a provenance statement. Consumers cannot verify the build source. You can add provenance to future versions without breaking existing consumers, it is additive. npm does not prevent publishing without provenance.
Is npm audit signatures the same as npm audit?
No. npm audit checks your dependencies against a database of known vulnerabilities. npm audit signatures verifies the cryptographic signatures of installed packages against the registry's signing keys. They are complementary, run both.
Can sigstore verification be bypassed if an attacker controls the GitHub Actions OIDC provider?
In theory yes, but that would require compromising GitHub's OIDC infrastructure, which is a different threat model than a compromised package maintainer account. The practical attacks sigstore prevents are: stolen npm tokens used to publish tampered packages, and compromised package registry serving different content than what the maintainer published.
Which npm packages currently have provenance attestations?
As of 2025, all packages published by major projects using GitHub Actions with --provenance include provenance. You can check any package with: npm view package-name --json | jq '.dist.attestations'. Coverage is growing rapidly following the XZ Utils and TanStack incidents.
How do I integrate sigstore provenance verification into a pull request gate so that dependency changes without valid provenance are blocked before merge?
Add a required GitHub Actions status check that runs npm audit signatures after every npm ci in your CI workflow. If the command exits non-zero, the check fails and the PR cannot merge. For stricter enforcement, write a custom script that calls npm view for each newly added dependency in the diff, checks for a .dist.attestations field in the returned JSON, and fails the check if any new dependency lacks provenance. You can extract the list of changed packages by comparing package-lock.json between the PR branch and main using jq. Over time, convert the warning-level absence of provenance to a hard failure as your dependency tree gains coverage, starting with the highest-risk dependency categories like authentication libraries and cloud SDK clients.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
