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

pkgproof

v0.0.1

Published

Block hallucinated & slopsquatted npm packages before they install — the pkgproof CLI.

Readme

pkgproof

Blocks hallucinated and slopsquatted npm & PyPI packages before they install — an explainable, agent-native guard.

⚠️ Pre-alpha (v0.0.1) — not for production use

pkgproof is under active development. Verdicts, APIs, and the bundled blocklist will change without notice. This early release reserves the name and shares progress — please don't depend on it yet.

License Tests npm blocklist PyPI blocklist Node MCP

AI coding agents invent package names, and attackers pre-register the ones models predictably hallucinate — a supply-chain attack called slopsquatting. pkgproof sits inside the install loop and returns a calibrated, explainable ALLOW | WARN | BLOCK verdict from deterministic signals — offline-first, in well under a millisecond, and it never installs or executes the package it judges.

It's not a theoretical guard. pkgproof caught [email protected] — a package carrying a postinstall infostealer dropper (behavior consistent with a DPRK campaign, by static analysis) that sat live and installable on npm for ~278 days, carrying no GHSA/CVE/OSV advisory at catch time, a prefix squat of pino (the node- prefix is a 5-character insertion, not a typo) — surfaced pre-install by the semantic judge, because its content didn't match its name.


TL;DR — quick start

Pre-alpha on npm. Published under the alpha tag as v0.0.1: install with npm install -g pkgproof@alpha. A bare npm install -g pkgproof intentionally won't resolve yet — this is early and under active change; you can also just build from source below.

# Build from source (the real path today):
git clone https://github.com/EastVillageTech/pkgproof
cd pkgproof
pnpm install
pnpm --filter pkgproof build

# Run it:
node packages/cli/dist/cli.js check express

# Pre-alpha, published under the alpha tag:
npm install -g pkgproof@alpha

A sample verdict — one PASS, one risk-signal FLAG:

# PASS — a known, popular package clears:
✓ ALLOW  express — known popular package

# FLAG — a heuristic risk signal (unverified, NOT a malware claim):
┌─────────────────────────────────────────────────────────────────────────────┐
│ ⚠ WARN  expres                                                              │
│ why:   "expres" looks like a typo of "express" — unverified, possible squat  │
│ fix:   if you meant "express", install that instead                          │
│ ref:   verify with the user before installing                                │
└─────────────────────────────────────────────────────────────────────────────┘

A WARN is a heuristic risk signal — "this looks wrong, a human should confirm" — never an accusation. A BLOCK is reserved for confirmed-evidence catches (a name on the confirmed-malicious blocklist, or a content-verified squat like node-pino).


Why pkgproof

Commercial scanners already do basic hallucination and typosquat detection. pkgproof does not claim to out-detect them — it publishes its own failed novel-detection experiments in the open. The honest differentiation is where and how it acts:

  • Pre-install, not post-install. npm audit reports CVEs after resolution; most scanners alert on a dashboard after the fact. pkgproof blocks at the install boundary via a PATH-shim, so a malicious postinstall never runs.
  • Agent-native and deterministic. A red-team drove real AI agents at a confirmed-BLOCK package: a weak agent installed it anyway — sometimes even after seeing an advisory. The deterministic pkgproof guard halted it regardless — the boundary holds no matter what the agent decides.
  • Explainable and open. Every verdict states WHAT, WHY, and the FIX in plain text. Apache-2.0, no cloud account, no opaque score.
  • Slopsquat-focused. The net-new AI threat: an LLM hallucinates a name an attacker pre-registered. pkgproof ships a readable blocklist of 37,953 npm names — 37,650 from the OSSF malicious-packages advisory DB, plus 362 mirrored npm security-seizures, plus 2 seeded compromised-version ranges (sources overlap; 37,953 unique) — and 11,398 PyPI names. Of the npm set, pkgproof independently surfaced 12 novel live squats — 1 (node-pino) payload-confirmed, 11 live-squat-shape awaiting deeper analysis.

See the honest comparison and threat model.


The four surfaces

One engine (@pkgproof/verify), one verdict vocabulary, four shipped, user-facing surfaces (CLI, install-guard, MCP, GitHub Action). Two more — the Cloudflare Worker and web /api/verify — are built but not deployed (see the roadmap).

1. CLI check — verify a name by hand

node packages/cli/dist/cli.js check langchain-community-helpers lodahs react
╔══════════════════════════════════════════════════════════════════════════╗
║ ⛔ BLOCK  lodahs                                                         ║
║ what:  npm seized this name for malware — a neutralized stub             ║
║ why:   "lodahs" is on the confirmed-malicious blocklist — do not install ║
║ fix:   install "lodash" instead — the real package                       ║
║ ref:   pkgproof check lodahs  ·  override (human only): --force          ║
╚══════════════════════════════════════════════════════════════════════════╝
✓ ALLOW  react — known popular package

Exit 2 on any BLOCK. CLI reference →

2. Guard shim — the real boundary in your install loop

pkgproof guard <pm> <args...> verifies first, then runs the real package manager only if nothing blocks. Install the PATH-shim (pkgproof init shell) and even a bare npm install — including an agent's — is guarded.

node packages/cli/dist/cli.js guard npm install node-pino
╔═════════════════════════════════════════════════════════════════════════════╗
║ ⛔ BLOCK  node-pino                                                         ║
║ why:   "node-pino" is on the confirmed-malicious blocklist — do not install ║
╚═════════════════════════════════════════════════════════════════════════════╝
⛔ pkgproof BLOCKED this install: node-pino. 'npm' was NOT run — nothing was written.

Works for npm · pnpm · yarn · bun · pip · poetry · uv. Guard reference →

3. MCP — a verify tool for your agent

Register the verify_package tool (Claude Code / Cursor / VS Code) so the agent checks a name before it installs. Structured output an agent can reason over:

{
  "verdict": "BLOCK",
  "package": "node-pino",
  "reason": "\"node-pino\" is on the confirmed-malicious blocklist — do not install",
  "confidence": 0.99,
  "suggestion": "pino",
  "blocklist_loaded": true,
  "gate_ok": true
}

gate_ok: false means signature coverage is degraded — an ALLOW is then not malware-verified. The measured lesson: the MCP hint informs the agent; the guard enforces. Use both. MCP reference →

4. GitHub Action — gate your CI

A composite action scans your lockfile (pkgproof scan --lockfile --json), emits SARIF 2.1.0 plus a step summary and inline annotations, and exits the scan contract code (BLOCK → 2) so a bad dependency fails the build.

- uses: EastVillageTech/pkgproof@v1
  with:
    paths: .
    strict: true
    sarif: true

Inputs: paths · working-directory · strict · sarif · sarif-file. Action reference →


What it checks

| Detector | What it flags | How | |---|---|---| | Existence | A name that 404s on the registry — a pure hallucination | Live registry lookup; newness is a gate, never a conviction | | Confusion | Typosquats & look-alikes (lodahslodash) | Damerau-Levenshtein distance + homoglyph / NFKC folding against 297 npm / 138 PyPI anchor names | | Signature blocklist | Confirmed-malicious names, exact + version-aware | 37,953 npm (37,650 OSSF advisory + 362 mirrored seizures + 2 seeded ranges; overlap → 37,953 unique) + 11,398 PyPI names; download-continuity checks | | Living corpus | Names today's models actually hallucinate | 410 catches and counting, mined by an always-running miner | | Semantic judge | Aged look-alikes whose content betrays the name | LLM name↔content coherence (what caught node-pino) — downgrade-only, opt-in, needs a local claude CLI |

Rules run in a fixed order (R0..R3 hard rules, then a 5-signal soft band), so the same name always gets the same verdict.


How it decides — and what it can't do

pkgproof is deliberate about the line between a proven catch and a guess:

  • BLOCK is evidence-backed: an exact hit on the confirmed-malicious blocklist, or a content-verified squat with a cited reason. These are the only verdicts framed as malware.
  • WARN is a heuristic risk signal — "this looks like a typo / is suspiciously new / thin" — explicitly unverified. It asks a human to confirm; it is never an accusation.
  • ALLOW means "nothing tripped," not "audited safe." A brand-new legitimate package is never blocked just for being new.

What it can't do: it is not a full malware scanner or a sandbox detonator. It does not execute or install anything it judges (a hard invariant). Deterministic verdicts (blocklist + heuristics) are fully offline, with no account. The optional semantic judge — the aged-look-alike edge that surfaced node-pino — requires a local claude CLI (account + network); it is downgrade-only and off by default, so CI stays fully offline and deterministic. It reasons over registry metadata, names, and published content — not runtime behavior. Treat it as a fast, explainable first gate in front of your package manager, layered with, not replacing, your other supply-chain controls.


Proof: the node-pino catch

pkgproof caught [email protected] on npm — a package that was clean by every metadata signal and malicious in its content, a prefix squat of the popular pino logger (node- prepended — a 5-character insertion, not a typo).

  • Caught pre-install on 2026-06-22 by the semantic judge, not typo-distance: its content didn't match its name — main pointed at ./lib/winston.js, its dependencies were winston's, and it shipped a postinstall dropper. The judge scored it 0.95.
  • Analyzed statically and offline (decrypted with openssl, never executed): a postinstall spawns a detached child that AES-256-CBC-decrypts a bundled license.list and eval()s a ~105 KB obfuscated infostealer targeting crypto wallets, the macOS Keychain, and browser credential stores.
  • Consistent with the DPRK "Contagious Interview" / BeaverTail campaign (C2 port :1224, dropper structure, targeting) — stated as consistent with, never a definitive attribution. No C2 host IP was reconstructed.
  • Dwell time: ~278 days (9.3 months) live and installable until pkgproof surfaced it. [email protected] specifically carried no GHSA/CVE/OSV advisory at catch time (now recorded in OSSF via our PR #1340, merged 2026-07-05). A sibling variant, pino-node, from the same campaign was already flagged on Snyk — pkgproof caught a different, still-unlisted variant of a known campaign.
  • Reported to npm 2026-07-02 (malware-removal report); the OSSF malicious-packages PR (#1340) is now merged. As of last check, npm has restricted the package page (403) but the tarball is still live and installable — takedown is npm's action and is not yet confirmed. Do not install it.

Full write-up with IOCs (no runnable payload): case study →.


Config & exit codes

Exit codes (the agent / CI contract):

| Code | Meaning | |---|---| | 0 | all ALLOW (or WARN without --strict) | | 1 | --strict and a WARN was seen (or a usage / internal error) | | 2 | a BLOCK was seen — installs MUST stop |

--force overrides a BLOCK (exit 0) and logs it to stderr — explicit and auditable. --json emits machine-readable output. A per-project .pkgproofrc.json can downgrade a matching heuristic WARN/BLOCK to ALLOW, but never a confirmed-malware BLOCK.

Useful commands: pkgproof status (blocklist freshness + count) · pkgproof demo (a hallucination, a typosquat, a real package) · pkgproof init shell (install the guard PATH-shim).


Links

  • Repository & full docs: https://github.com/EastVillageTech/pkgproof
  • CLI reference: https://github.com/EastVillageTech/pkgproof/blob/main/docs/cli.md
  • Install guard: https://github.com/EastVillageTech/pkgproof/blob/main/docs/install-guard.md
  • MCP integration: https://github.com/EastVillageTech/pkgproof/blob/main/docs/mcp.md
  • GitHub Action: https://github.com/EastVillageTech/pkgproof/blob/main/docs/github-action.md
  • How detection works: https://github.com/EastVillageTech/pkgproof/blob/main/docs/how-detection-works.md
  • Threat model: https://github.com/EastVillageTech/pkgproof/blob/main/docs/threat-model.md
  • node-pino case study: https://github.com/EastVillageTech/pkgproof/blob/main/docs/case-study-node-pino.md
  • Security policy: https://github.com/EastVillageTech/pkgproof/blob/main/SECURITY.md

Apache-2.0 · pkgproof never installs or executes the package it judges.