DEV Community

Pico
Pico

Posted on • Originally published at getcommit.dev

Your pnpm monorepo has 4 CRITICAL packages. Here's how to find them in 10 seconds.

A monorepo multiplies your dependency surface. Each workspace has its own package.json, its own dependencies, its own attack surface. npm audit doesn't aggregate across workspaces. Neither does pnpm audit.

I ran a scan across a typical pnpm monorepo with 4 workspaces — apps/web, apps/api, packages/ui, packages/shared. Here's what came back:

Monorepo: 4 workspaces → 10 unique external dependencies (npm)

Package   Risk          Score  Publishers  Downloads   Age
clsx      🔴 CRITICAL   70     1           95.3M/wk    7.4y
lodash    🔴 CRITICAL   81     1           149.2M/wk   14y
zod       🔴 CRITICAL   86     1           164.4M/wk   6.2y
axios     🔴 CRITICAL   86     1           104.2M/wk   11.7y
react     🟢 HEALTHY    88     2           125.2M/wk   14.5y
express   🟢 HEALTHY    90     5           96.2M/wk    15.4y

⚠  4 CRITICAL packages found.
Enter fullscreen mode Exit fullscreen mode

4 out of 10 unique dependencies are CRITICAL. Not because of known CVEs — because each one has a single npm publisher with >10M weekly downloads.

That's the exact pattern behind the axios supply chain attack (March 30, 2026) and the LiteLLM compromise before it. Stolen credentials → malicious publish → millions of machines exposed. One person's npm token is the entire attack surface.

The monorepo blind spot

pnpm audit checks for known CVEs. It doesn't tell you:

  • How many people can publish each package
  • Whether your most-downloaded dependency has a single point of failure
  • Which packages across ALL your workspaces share this risk

In a monorepo, the same risky package might appear in 3 workspaces. You need the cross-workspace view.

One command

npx proof-of-commitment --file pnpm-workspace.yaml
Enter fullscreen mode Exit fullscreen mode

This:

  1. Parses your pnpm-workspace.yaml glob patterns (apps/*, packages/*)
  2. Reads package.json from every workspace + root
  3. Merges and deduplicates all external dependencies
  4. Excludes internal workspace packages (they're yours, not a supply chain risk)
  5. Scores each package on behavioral signals — publisher count, age, release consistency, download trend

Auto-detection

If you pass the lock file and a workspace file exists next to it, it detects the monorepo automatically:

npx proof-of-commitment --file pnpm-lock.yaml
# Monorepo: 4 workspaces → 10 unique external dependencies (npm)
# (auto-detected pnpm-workspace.yaml next to pnpm-lock.yaml)
Enter fullscreen mode Exit fullscreen mode

CI/CD integration

JSON output for pipelines:

npx proof-of-commitment --file pnpm-workspace.yaml --json | jq '.criticalCount'
# 4
Enter fullscreen mode Exit fullscreen mode

Or use the GitHub Action:

name: Supply Chain Audit
on:
  pull_request:
    paths: ['**/package.json', 'pnpm-lock.yaml']

jobs:
  audit:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: piiiico/commit-action@v1
        with:
          fail-on-critical: true
          comment-on-pr: true
Enter fullscreen mode Exit fullscreen mode

What CRITICAL means

A package is flagged CRITICAL when it has:

  • 1 npm publisher (the person with npm publish access — distinct from GitHub contributors)
  • >10M weekly downloads

zod has 30+ GitHub contributors but 1 npm publisher. If that one token gets stolen, 164M weekly installs get the payload. GitHub contributor count is irrelevant to publish-access risk.

What this doesn't replace

This is not a CVE scanner. It doesn't replace pnpm audit or Snyk or Socket. It measures a different attack surface — behavioral commitment and publisher concentration risk. Use both.

The question pnpm audit answers: does this package have a known vulnerability?

The question behavioral scoring answers: if this package gets compromised tomorrow, how bad is the blast radius?


proof-of-commitment is open source. v1.5.0 shipped today with pnpm workspace support.

npx proof-of-commitment --file pnpm-workspace.yaml — try it on your monorepo.

Top comments (0)