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

vetpkg

v0.1.0

Published

Catch hallucinated and squatted packages before an AI agent installs them. MCP server + CLI, zero dependencies.

Downloads

33

Readme

vetpkg

Stop AI coding agents installing packages that don't exist.

Zero dependencies. Works as an MCP server, a CLI, or a library.

npx vetpkg express-async-router-utils-pro
 none  express-async-router-utils-pro         risk 100
        ! No package by this name exists on the registry. If an AI assistant
          suggested it, it was invented.
        ! Closest real package is "express-async-router" — every word in the
          shorter name appears in "express-async-router".
        => Do not install. The intended package was most likely "express-async-router".

The problem

AI coding assistants recommend packages that do not exist about 19.7% of the time (576,000-sample study). Open-weight models average 21.7%; commercial models around 5.2%.

That alone would just be annoying. What makes it dangerous is that the hallucinations repeat. When researchers re-ran 500 prompts that had produced a fabricated package name, 43% returned the same fabricated name every single time.

A predictable hallucination is an attackable one. The attack is called slopsquatting:

  1. A model invents a plausible package name that has never existed.
  2. An attacker registers that exact name on npm.
  3. The next developer — or autonomous agent — who runs the install command pulls attacker-controlled code straight into the build.

This is not hypothetical. unused-imports is the textbook case: models hallucinate it instead of the real eslint-plugin-unused-imports. react-codeshift was claimed in January 2026.

Meanwhile over 50% of organisations have already had an outage or security incident from AI-generated code using outdated or wrong APIs (Snyk). Models are trained infrequently — a model shipped this summer can be confidently wrong about a library that changed a year ago.

What vetpkg does

It answers one question, before anything gets installed:

Is this a real, established package — or did a model invent it?

It checks the live registry and scores what it finds:

| Signal | Why it matters | |---|---| | Existence | The package may simply not be real. | | Name similarity | Catches three distinct shapes — typos, token subsets, and reshapes. | | Age | Slopsquats are registered after the hallucination becomes common. | | Adoption | Real packages have sustained downloads; squats have almost none. | | Release history | One version, published once, never updated is a throwaway registration. | | Provenance | No linked repository means the code can't be reviewed. | | Security holds | npm seizes malicious packages; that's detected and hard-blocked. |

No single signal is proof. The giveaway is the combination — brand new, barely downloaded, published once, no repository, and named a near-miss of something popular. Real packages essentially never look like that.

Why name similarity needs three mechanisms

Edit distance alone misses the most common real-world shape:

| Shape | Example | Caught by | |---|---|---| | Typo | expres → express | edit distance 1 | | Subset | unused-imports → eslint-plugin-unused-imports | edit distance is 14 — only token analysis catches this | | Reshape | node_fetch → node-fetch | normalisation |

The subset shape is exactly what models produce when they "simplify" a name they half-remember, and it's the shape of the documented unused-imports incident. A tool checking only edit distance will miss it.

Use it as an MCP server

This is the point. A CLI only helps if you remember to run it. An MCP server sits inside the agent's tool loop, so the check happens automatically, at the moment the agent is about to install something.

Claude Desktop / Claude Code — add to claude_desktop_config.json:

{
  "mcpServers": {
    "vetpkg": {
      "command": "npx",
      "args": ["-y", "vetpkg", "vetpkg-mcp"]
    }
  }
}

Cursor — add to .cursor/mcp.json:

{
  "mcpServers": {
    "vetpkg": { "command": "npx", "args": ["-y", "vetpkg", "vetpkg-mcp"] }
  }
}

Two tools are exposed:

  • check_package — verify one package
  • check_packages — verify several at once

Then tell your agent, once: "Always check packages with vetpkg before installing them."

Use it as a CLI

# check specific packages
npx vetpkg express react lodash

# check everything in package.json
npx vetpkg scan

# production dependencies only
npx vetpkg scan --prod

# machine-readable
npx vetpkg express --json

Exits non-zero if anything is suspicious, blocked, or missing — so it works as a CI gate or a pre-install hook:

{ "scripts": { "preinstall": "vetpkg scan || true" } }

Use it as a library

import { checkPackage } from 'vetpkg';

const result = await checkPackage('unused-imports');

result.verdict;         // 'trusted' | 'caution' | 'suspicious' | 'blocked' | 'not_found'
result.risk;            // 0–100
result.reasons;         // [{ severity, text, points }]
result.recommendation;  // plain-English next step
result.similar;         // closest real packages, if any

FAQ

Does this replace npm audit or Socket? No, and it isn't trying to. npm audit finds known vulnerabilities in packages you already trust. vetpkg asks whether the package should be trusted at all — whether it's real, and whether it's what you meant. Run both.

Why not just check if the package exists? Because the dangerous case is that it does exist. Once an attacker registers a hallucinated name, an existence check passes and hands you the payload. Existence is the easy half.

Will it flag legitimate new packages? Sometimes, and deliberately. A brand-new package with no downloads is genuinely unverifiable — that's caution, not suspicious. The scoring only reaches suspicious when several independent signals agree.

Does it flag popular packages with similar names? No. Packages with real adoption are exempt from name-similarity scoring — express is not warned about for resembling cypress. Slopsquats are by construction new and unused, so similarity only carries risk for packages that aren't established.

Does it send my dependency list anywhere? No. It queries the public npm registry directly from your machine. There is no telemetry and no account.

Which registries are supported? npm today. PyPI is next — the same attack works there, and the research covering it sampled both.

Why zero dependencies? A tool that vets your dependency tree shouldn't arrive with one.

How scoring works

| Verdict | Risk | Meaning | |---|---|---| | trusted | 0–27 | Established, normal publication history. | | caution | 28–54 | Unverifiable or unusual. Look before installing. | | suspicious | 55–99 | Several signals agree. Do not install without checking. | | blocked | 100 | Security-held by npm. Never install. | | not_found | 100 | Does not exist. If an AI suggested it, it was invented. |

Limitations

Worth being straight about:

  • A determined attacker can fake the signals. Downloads can be inflated and repositories can be fabricated. This raises the cost of the attack; it does not make it impossible.
  • The bundled name corpus is a snapshot. A squat targeting a package that isn't in the corpus won't be caught by similarity — though the age, adoption and provenance signals still apply.
  • New legitimate packages score low. That's correct behaviour, not a bug, but it means low scores need judgement rather than blind obedience.

Licence

MIT