npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pnpm-shield

v1.0.1

Published

Supply chain attack protection audit tool for pnpm projects

Readme

🛡️ pnpm-shield

Supply chain attack protection audit tool for pnpm projects.

npm version Node.js License: MIT Zero dependencies GitHub

pnpm-shield audits your pnpm project and developer environment against the most common supply chain attack vectors — postinstall script injection, dependency confusion, phantom dependencies, and accidental npm usage. It runs 13 checks, explains every finding with attack vectors and remediation steps linked to official docs, and can auto-fix all of them interactively.


Why this matters

The npm registry is the largest software registry in the world — and one of the most targeted. Attackers abuse postinstall scripts, typosquatting, and account takeovers to execute arbitrary code on every machine that runs npm install or pnpm install. The attacks below all share one trait: they would have been stopped by a correctly configured pnpm environment.

| Incident | Year | Attack vector | Source | |---|---|---|---| | event-stream backdoor | 2018 | Malicious postinstall injected after maintainer handover | Snyk | | eslint-scope credential theft | 2018 | Stolen npm credentials → postinstall exfiltrated .npmrc tokens | ESLint | | ua-parser-js takeover | 2021 | npm account hijacked → cryptominer + RAT via postinstall | GitHub Advisory | | dependency confusion | 2021 | Public package shadows internal name, executes on install | Alex Birsan | | node-ipc sabotage | 2022 | Maintainer added destructive postinstall targeting Russian IPs | Socket.dev | | colors + faker protest | 2022 | Maintainer corrupted own packages, breaking thousands of projects | Snyk | | xz-utils backdoor | 2024 | 2-year social engineering → malicious build script in release tarball | Openwall | | polyfill.io CDN hijack | 2024 | Domain acquired → CDN injected malicious JS into 100k+ sites | Sansec | | nx package compromise | Aug 2025 | Malicious nx versions published → credential theft + filesystem scan | Arctic Wolf | | Shai-Hulud worm | Sep 2025 | Self-replicating npm worm stole cloud tokens and re-published infected packages | Wiz | | axios maintainer compromise | Mar 2026 | Hijacked maintainer account → postinstall RAT in axios v1.14.1 | Arctic Wolf | | TanStack / TeamPCP campaign | Apr 2026 | Poisoned CI/CD cache → malicious publishes across TanStack ecosystem | Cybernews |

💡 Every postinstall attack in this list is blocked by ignore-scripts=true. The dependency confusion attacks are mitigated by a strict pnpm-lock.yaml and the packageManager field enforced by Corepack. pnpm-shield checks for all of these protections.


Installation

# Run directly without installing (recommended for one-off audits):
pnpm dlx pnpm-shield

# Install globally:
pnpm add -g pnpm-shield

# Add as a dev dependency in your project:
pnpm add -D pnpm-shield

Zero production dependencies. Everything uses Node.js built-ins.


Usage

# Run in the root of your project:
pnpm-shield

# Same command, shorter alias:
pnpm-check

# CI mode — non-interactive, exits with code 1 on failures:
pnpm-shield --ci

# Show help:
pnpm-shield --help

# Show version:
pnpm-shield --version

Interactive menu

After the audit runs, an interactive prompt lets you explore and fix findings without leaving the terminal.

Commands

| Command | Action | |---------|--------| | ? | Open an arrow-key browser across all 13 checks — navigate with ↑↓, press Enter to read documentation | | ?N | Read docs for check N directly, e.g. ?3 | | fix | Open a visual multi-selector for fixes — navigate with ↑↓, toggle with Space, confirm with Enter | | all | Apply all auto-fixable items at once | | q | Quit |

Documentation panel

Every check has an integrated documentation panel showing:

  • Why it matters — the security rationale
  • Attack vector — a concrete attack scenario
  • How to fix — step-by-step remediation commands
  • Official references — links to pnpm docs, Node.js docs, and security post-mortems

What it checks

pnpm-shield runs 13 security checks across three categories. All non-passing checks support auto-fix.

🖥 Environment

| # | Check | Severity | Auto-fix | |---|-------|----------|---------| | 1 | pnpm is installed and in PATH | CRITICAL | — | | 2 | Shell alias npm → pnpm | HIGH | ✅ Adds alias to shell config | | 3 | Corepack enabled and managing pnpm | HIGH | ✅ Runs corepack enable pnpm | | 4 | No foreign lockfiles (package-lock.json, yarn.lock, bun.lockb) | CRITICAL | ✅ Deletes foreign lockfiles |

⚙️ pnpm / npm Configuration

| # | Check | Severity | Auto-fix | |---|-------|----------|---------| | 5 | Global ignore-scripts = true | CRITICAL | ✅ pnpm config set ignore-scripts true | | 6 | Local .npmrc: ignore-scripts=true | HIGH | ✅ Appends to .npmrc | | 7 | Local .npmrc: save-exact=true | MEDIUM | ✅ Appends to .npmrc | | 8 | Local .npmrc: shamefully-hoist=false | LOW | ✅ Appends to .npmrc | | 9 | Local .npmrc: engine-strict=true | MEDIUM | ✅ Appends to .npmrc |

📦 package.json Hardening

| # | Check | Severity | Auto-fix | |---|-------|----------|---------| | 10 | pnpm.onlyBuiltDependencies whitelist | HIGH | ✅ Adds [] to package.json | | 11 | packageManager field pinned to [email protected] | HIGH | ✅ Sets current pnpm version | | 12 | engines.node range specified | MEDIUM | ✅ Sets >= current Node major | | 13 | pnpm-lock.yaml present | HIGH | ✅ Runs pnpm install |


Grading

After the audit, your project receives a security grade:

| Grade | Score | Meaning | |-------|-------|---------| | A+ | ≥ 92% | Fortress — all critical paths hardened | | A | ≥ 84% | Excellent — minor optional improvements available | | B | ≥ 76% | Good — a few medium-risk items to address | | C | ≥ 60% | Fair — notable gaps that should be closed | | D | < 60% | Needs attention — critical or multiple high failures |

Score = passed checks + 0.5 × warnings.


Check details

1. pnpm installed — CRITICAL

pnpm is the only mainstream package manager with onlyBuiltDependencies whitelisting, per-project ignore-scripts, and a content-addressable store with integrity verification.

corepack enable pnpm
# or:
curl -fsSL https://get.pnpm.io/install.sh | sh

📎 pnpm Installation


2. Shell alias npm → pnpm — HIGH ✅

Even with pnpm fully configured, typing npm install by muscle memory invokes the real npm binary. npm ignores your .npmrc, your pnpm-lock.yaml, and your onlyBuiltDependencies whitelist.

echo 'alias npm=pnpm' >> ~/.zshrc && source ~/.zshrc

📎 Typosquatting attacks


3. Corepack managing pnpm — HIGH ✅

Corepack (built into Node.js ≥ 16.9) reads "packageManager" in package.json and blocks npm and yarn project-wide. It also ensures every developer uses the exact same pnpm version.

corepack enable
corepack enable pnpm

📎 Corepack docs · pnpm + Corepack


4. No foreign lockfiles — CRITICAL ✅

A package-lock.json or yarn.lock alongside pnpm-lock.yaml creates two conflicting sources of truth. CI systems may pick the wrong one, installing different (potentially malicious) resolved versions.

rm package-lock.json yarn.lock bun.lockb
pnpm install
git add pnpm-lock.yaml

📎 Dependency confusion attack


5. Global ignore-scripts=true — CRITICAL ✅

Packages can declare postinstall, preinstall, and install lifecycle scripts that run arbitrary shell commands. This is the primary vector for supply chain attacks (event-stream 2018, node-ipc 2022, xz-utils 2024).

pnpm config set ignore-scripts true

Note: With ignore-scripts=true, packages that legitimately need build scripts (e.g. esbuild, sharp) will break. Use check #10 (onlyBuiltDependencies) to whitelist exactly those packages.

📎 pnpm ignore-scripts · event-stream post-mortem


6. Local .npmrc: ignore-scripts=true — HIGH ✅

The global config can differ across machines and CI environments. A local .npmrc commits the rule into the repository, protecting every developer and every CI runner regardless of their global config.

echo "ignore-scripts=true" >> .npmrc
git add .npmrc

7. save-exact=true — MEDIUM ✅

By default pnpm saves deps with a ^ prefix (e.g. ^1.2.3), allowing any compatible update. An attacker who compromises a package can publish 1.2.4 with malicious code and every project using ^1.2.3 adopts it on the next install.

echo "save-exact=true" >> .npmrc

📎 Semver hijacking


8. shamefully-hoist=false — LOW ✅

pnpm uses a strict, isolated node_modules layout by default. shamefully-hoist=true flattens it like npm, allowing packages to import dependencies they never declared (phantom dependencies).

echo "shamefully-hoist=false" >> .npmrc

📎 Phantom dependencies


9. engine-strict=true — MEDIUM ✅

Some security patches are Node.js-version-specific. Running code on an EOL Node version may miss critical fixes.

echo "engine-strict=true" >> .npmrc

📎 Node.js release schedule


10. pnpm.onlyBuiltDependencies — HIGH ✅

Even with ignore-scripts=true, you may need certain packages to run build scripts (e.g. esbuild, sharp). This whitelist gives surgical, auditable control over which packages may run scripts.

// package.json
{
  "pnpm": {
    "onlyBuiltDependencies": ["esbuild", "sharp"]
  }
}

An empty array [] blocks all postinstall scripts without exception.

📎 onlyBuiltDependencies


11. packageManager field — HIGH ✅

Tells Corepack the exact package manager and version the project requires. Corepack will then block npm and yarn and auto-download the correct pnpm version for any contributor.

// package.json
{
  "packageManager": "[email protected]"
}

📎 packageManager field


12. engines.node range — MEDIUM ✅

Declares the minimum Node.js version. Combined with engine-strict=true, pnpm refuses to install on incompatible environments, preventing use of EOL runtimes with known CVEs.

// package.json
{
  "engines": { "node": ">=20" }
}

📎 engines field


13. pnpm-lock.yaml present — HIGH ✅

The lockfile pins exact resolved versions AND SHA-512 integrity hashes for every package in the full dependency tree. Without it, pnpm install resolves versions fresh each time and can silently adopt a compromised release.

pnpm install      # generates pnpm-lock.yaml
git add pnpm-lock.yaml
# Never add pnpm-lock.yaml to .gitignore!

📎 pnpm lockfile format · Should lockfiles be committed?


CI/CD integration

GitHub Actions

# .github/workflows/security.yml
name: Security Audit

on: [push, pull_request]

jobs:
  pnpm-shield:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: pnpm dlx pnpm-shield --ci

Native git pre-commit hook (no extra dependencies)

cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
pnpm-shield --ci
EOF
chmod +x .git/hooks/pre-commit

Recommended baseline configuration

.npmrc

ignore-scripts=true
save-exact=true
shamefully-hoist=false
engine-strict=true

package.json additions

{
  "packageManager": "[email protected]",
  "engines": { "node": ">=20" },
  "pnpm": {
    "onlyBuiltDependencies": []
  }
}

Project structure

pnpm-shield.js        ← Entry point (20 lines)
lib/
  colors.js           ← ANSI color constants
  docs.js             ← Per-check documentation + official references
  checks.js           ← Runs all 13 security checks
  ui.js               ← Terminal output (header, results, doc panel, summary)
  selector.js         ← Raw TTY arrow-key interactive selector (zero deps)
  fixes.js            ← Auto-fix implementations for all 13 checks
  runner.js           ← Orchestrates the full audit + interactive menu

Contributing

Pull requests are welcome. To add a new check:

  1. Add the result in lib/checks.js with a docKey and fix key
  2. Add documentation in lib/docs.js with why, attack, fix, and refs
  3. Add a fix handler in lib/fixes.js

License

MIT