Skip to content
Fran Gonzalez
← Back to blog
(updated Jul 16, 2026)·Clanker·7 min read

Beyond Version Checks: Provenance and Behavioral Security

Lockfiles, cooldowns, and exclusion lists are necessary but not sufficient. Provenance verification and behavioral analysis catch the attacks they miss.

Some matmuls wrote this slop, sorry. My goal with this content is to document some work I (a real human bean) do while poking the Clanker, and try to learn something along the way.

The first three posts in this series covered version-level controls: pinning tools, cooling off new releases, managing exclusions. Those controls reduce several common risks, but they do not inspect what a package does or prove that its build workflow was trustworthy.

Note

Fact-checked on 2026-07-16 against pnpm 11.10.0, npm’s registry-signature and provenance documentation, and the cited incident report.

In April 2026, the TanStack/router repository was compromised through a CI workflow manipulation1. The attacker published malicious packages with valid SLSA provenance, because the packages were genuinely built by the repository’s own pipeline. The pipeline’s internal state was compromised, but the build environment was legitimate. Provenance verified correctly. Version checks passed. The attack relied on behavioral patterns that no version-level control can catch.

Provenance Verification

What provenance tells you

When a package is published with --provenance on npm, the registry stores a Sigstore-signed attestation that links the package to:

  • The source repository and commit
  • The CI workflow that built it
  • The build environment (GitHub Actions OIDC token)

This is roughly SLSA Build Level 22, the package was built on a hosted platform, and the provenance is cryptographically signed so it can’t be forged.

Registry signatures are separate from provenance

pnpm 11.1 added pnpm audit signatures. It verifies each installed package’s ECDSA registry signature against the public keys exposed by that registry at /-/npm/v1/keys. I added it as a CI step:

- name: Verify package signatures
  run: pnpm audit signatures

A successful result establishes that the registry signature is present and cryptographically valid. It does not establish which CI workflow built the package, whether npm provenance exists, or whether the published code is benign. npm provenance is a separate signed attestation that links a package to source and build information. pnpm’s trustPolicy uses that trust evidence to detect a downgrade between releases.

What provenance doesn’t tell you

Provenance confirms which pipeline built a package, not whether that pipeline was clean. The TanStack/router incident demonstrated this: the attacker compromised the workflow itself, so the provenance was valid. The package was built by the right pipeline, but the pipeline was doing the wrong thing.

Provenance catches impersonation and token theft. It doesn’t catch pipeline compromise.

Behavioral Analysis

The install-time execution problem

Install time is a high-risk point in the npm lifecycle because lifecycle scripts execute package-controlled code with the permissions of the calling process.3 Depending on the environment, that process may be able to read:

  • ~/.npmrc (registry tokens)
  • ~/.ssh/ (SSH keys)
  • GITHUB_TOKEN (in CI)
  • Environment variables (secrets, API keys)

allowBuilds in pnpm v11 blocks scripts from unreviewed packages. But for packages I’ve approved, the script runs with full privileges. If an approved package is later compromised (through a maintainer account takeover, for example), the next pnpm install executes the malicious script.

Socket.dev

Socket monitors packages for behavioral red flags4:

  • Install-time network connections: a package that opens sockets during postinstall is suspicious
  • Filesystem access: reading files outside the package directory (especially ~/.ssh, ~/.npmrc)
  • Shell command execution: spawning child processes that aren’t part of the build
  • Obfuscated code: dynamically decoded payloads, eval chains
  • New binary introductions: a package that didn’t previously ship binaries suddenly adds one

Socket integrates with GitHub as a PR check. When a dependency update introduces a package with suspicious behavior, the PR gets flagged.

The TanStack lesson

The TanStack/router attacker had valid provenance. Version checks passed. The only signal was behavioral: the compromised pipeline was doing something it hadn’t done before5. Behavioral analysis catches this class of attack because it asks “what is this package doing?” rather than “is this package the right version?”

Private Registry Proxy

For projects with internal packages, a private registry proxy (Verdaccio, Artifactory, Cloudflare Workers) adds another gate:

  • Route all npm traffic through the proxy
  • Block known malicious versions at the proxy level
  • Cache and audit every download
  • Enforce organizational policies (no install scripts from untrusted sources)

This prevents dependency confusion attacks and gives a central point to enforce policies that package managers alone can’t.

SBOM Generation

A Software Bill of Materials (SBOM) is a machine-readable inventory of every dependency in your project. When a new vulnerability is disclosed, I can instantly check whether I’m affected.

Generate an SBOM with:

pnpm sbom --format spdx-json > sbom.json

For static sites this is low-risk. For anything that handles user data, an SBOM is the difference between “we’ll check” and “we know.”

The Full Stack

The layers from this series, in order of what to implement first:

LayerWhat it catchesEffort
Lockfile + --frozen-lockfileUnexpected version changesLow
minimumReleaseAgeFreshly published compromised packagesLow
allowBuildsUnreviewed install scriptsLow
SHA-pinned CI actionsCompromised mutable tagsLow
pnpm audit in CIKnown vulnerabilitiesLow
Renovate/Dependabot with cooldownStale dependencies, update velocityMedium
pnpm audit signaturesMissing or invalid registry signaturesLow
trustPolicy: no-downgradeDowngrades in available publication trust evidenceLow
Socket.devBehavioral anomalies in dependenciesMedium
Private registry proxyDependency confusion, central policy enforcementMedium
SBOM generationImpact analysis for new CVEsLow

No single layer is complete. Each one catches attacks that the others miss. The goal is to make supply chain attacks expensive enough that attackers move on.

What I’d Do Differently

I’d add pnpm audit signatures to CI earlier as an integrity check for registry signatures. I would document it beside provenance controls rather than treating it as provenance verification. I’d also evaluate Socket.dev for projects that handle user data because behavioral analysis covers activity that version and signature checks do not inspect.

The private registry proxy is the one I’d skip for a static blog. It’s worth the setup for anything with user-facing APIs or sensitive data, but the overhead isn’t justified for a site that only serves HTML.

References

Footnotes

  1. The full incident analysis is Unit 42’s April 2026 investigation. The key finding: the attacker compromised the CI workflow definition itself, not a maintainer token. This meant the build, signing key, and provenance attestation were all legitimate; the pipeline was simply building the wrong artifact.

  2. SLSA Build Level 2 requires the build to run on a hosted platform with signed provenance. It does not verify that the build pipeline’s source code or workflow definition is untampered; that’s Build Level 3.

  3. npm install scripts run with the permissions of the calling user and process. The npm lifecycle documentation lists preinstall, install, and postinstall as the scripts that run during package installation. In CI environments, this often means access to secrets and deployment credentials.

  4. Socket’s detection methodology categorizes risks into supply chain, quality, maintenance, license, and vulnerability signals. Install-time execution and network access are flagged as critical behavioral indicators.

  5. The Unit 42 report notes the behavioral anomaly was the tell: the compromised package performed network requests during installation that the legitimate version never did. Behavioral analysis tools like Socket detect these anomalies by comparing a package’s behavior against its historical baseline.

This post was written with AI assistance.