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

slopshield

v0.3.0

Published

Block AI-hallucinated and typosquatted npm packages before they install.

Readme

slopshield

Block AI-hallucinated and typosquatted npm packages before you install them.

npm version CI node license: MIT

slopshield in action

AI coding assistants routinely suggest packages that don't exist (~1 in 5 recommendations) or are lookalikes of real ones. Because the hallucinated names recur, attackers pre-register them ("slopsquatting") so the install pulls malware. Dependabot and Snyk only catch known-vulnerable, known packages — they're blind to nonexistent-but-soon-malicious names. slopshield fills that gap with fast heuristics over public npm registry data, and — unlike static scanners that read your files after the fact — it can intercept the install before the package lands.

npm install -g slopshield
slopshield express react lodash     # → all safe, exit 0
slopshield expresss reqeust         # → flags lookalikes of express / request

Or run it once without installing: npx slopshield <pkg>.

How it works

Each package gets a risk verdict (safe / medium / high / critical, or unknown when the registry can't be reached) with plain-language reasons, from five heuristics:

  1. Nonexistent — not registered in npm (critical).
  2. New — first published within the last 30 days.
  3. Low downloads — near-zero weekly downloads.
  4. Lookalike — a near-miss (edit distance) of a much more popular package; the reason names the suspected target.
  5. Known-slop — matches a curated list of documented hallucination/typosquat names.

It is warn-by-default (a single heuristic never blocks) and fail-open (a registry outage yields unknown, never a false "safe"). A lookalike of an existing package warns at medium; it only escalates to a blocking high/critical when signals combine (e.g. lookalike and brand-new and near-zero downloads) or the name simply doesn't exist. Thresholds live in one file (src/config.ts) — the false-positive dial.

Measured on a curated corpus (npm run validate): 100% recall on nonexistent + known-typosquat names at the default gate, and 0 false positives across 34 of the most-installed npm packages.

How it compares

| | slopshield | Dependabot / Snyk | Static "slop" file scanners | |---|---|---|---| | Catches nonexistent / hallucinated names | ✅ | ❌ (only known packages) | partial | | Catches typosquat / lookalike names | ✅ | ❌ | partial | | Known-CVE / SCA / SBOM | ❌ (not the goal) | ✅ | ❌ | | Blocks at install time, before code lands | ✅ | ❌ (reports after) | ❌ (scans files) | | Runtime dependencies | zero | many | varies |

slopshield is complementary to Dependabot/Snyk — keep using them for known-CVE coverage — and it acts at the moment of npm install, not as an after-the-fact file scan.

Requirements

  • Node.js 18+ (uses the built-in fetch).
  • Zero runtime dependencies — a supply-chain tool should have the smallest possible attack surface.

Usage

# Check one or more package names
slopshield express react lodash            # → all safe, exit 0
slopshield expresss reqeust                # → flags lookalikes of express / request

# Scan a project's package.json (deps, devDeps, optional, peer) or a newline list
slopshield --file package.json

# Machine-readable output for CI
slopshield --file package.json --json

# Choose how strict the exit code is (default: high)
slopshield expresss --fail-on medium       # exit 1 on medium or above

Options

| Option | Description | |---|---| | --file <path> | Read names from a package.json or a newline-delimited list | | --json | Output a JSON array of verdicts (always the full set, plain, never colored) | | --quiet | Print only flagged packages (hide safe), plus a one-line summary | | --fail-on <level> | Exit non-zero at this level or above: safe|medium|high|critical|none (default high) | | --no-color | Disable ANSI color | | --version | Print the installed version | | --help | Show help |

Exit codes: 0 = nothing at/above the fail-on level; 1 = a risky package was found; 2 = usage error. unknown verdicts never fail the run.

Summary line: scans of more than one package (and any --quiet run) end with a one-line tally, e.g. 6 checked — 1 critical, 2 high, 1 medium, 2 safe (all safe when nothing is flagged). Pair it with --quiet to keep CI logs to just the problems plus the count. The exit code is always computed over every package, regardless of --quiet.

Colored output: verdicts are color-coded (green safe → yellow medium → red high → bold-red critical → dim unknown) when writing to a terminal. Color is auto-disabled when output is piped or redirected, and honors the NO_COLOR and FORCE_COLOR environment variables plus the --no-color flag (precedence: --no-color > FORCE_COLOR > NO_COLOR > TTY). --json is always plain.

Install guard

Catch risky packages before they install:

# Gate by exit code (no install) — ideal for CI and shell hooks
slopshield guard express lodash            # silent, exit 0
slopshield guard expresss --block          # exit 1, names the typo'd target

# Wrap an install: pre-check, then run "npm install …" verbatim if it passes
slopshield install express --save-dev
slopshield install some-ai-suggested-pkg   # warns (or blocks) before npm runs

# Transparent adoption: shadow npm so every "npm install" is auto-checked
eval "$(slopshield init-shell zsh)"        # add to ~/.zshrc  (supports bash|zsh|fish)

Policy (warn by default; block is opt-in) lives in package.json:

{
  "slopshield": {
    "mode": "block",
    "failOn": "high",
    "allow": ["my-internal-pkg"]
  }
}
  • warn (default): prints reasons; in an interactive terminal it asks before installing; in CI it proceeds.
  • block: refuses to install anything at or above failOn — npm is never spawned; risky packages below failOn are warnings.
  • Non-registry specifiers (git/url/file) and unparseable args pass through unchecked (fail-open).
  • Not a sandbox: the guard blocks risky names before install; it does not sandbox a safe package's lifecycle scripts. npm-only for now (guard works for any package manager via shell integration).

GitHub Action

Add slopshield to CI in a few lines — it fails the job when a risky package is found:

name: slopshield
on: [pull_request]

permissions:
  contents: read

jobs:
  slopshield:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: khoi03/[email protected]
        with:
          fail-on: high        # exit non-zero at this level or above

By default it scans package.json and prints only flagged packages plus a summary.

| Input | Default | Description | |---|---|---| | file | package.json | Manifest or newline list to scan (ignored when packages is set) | | packages | — | Space-separated package names to scan instead of a file | | fail-on | high | Exit non-zero at this level or above: safe|medium|high|critical|none | | quiet | true | Print only flagged packages plus the summary line | | version | latest | slopshield version to run (pin for reproducible CI, e.g. 0.2.0) | | working-directory | . | Directory to run the scan in |

The action runs the published CLI via npx (no extra install). Pin version for reproducible runs.

AI-agent guard

AI coding agents are the biggest source of slopsquatting — they confidently suggest packages that don't exist. slopshield can sit between the agent and your registry so a hallucinated install is caught the moment it's proposed. Two integrations, both zero-dependency and built on the same engine:

MCP server

Expose a check_package tool to any MCP-capable agent, so it can verify a name before suggesting or installing it:

slopshield mcp   # speaks MCP over stdio

Register it with your client. For Claude Code:

claude mcp add slopshield -- slopshield mcp

Or add it to your MCP client config directly:

{
  "mcpServers": {
    "slopshield": { "command": "slopshield", "args": ["mcp"] }
  }
}

The agent calls check_package with one or more names and gets back a verdict (safe/medium/high/critical/unknown) and reasons for each.

Claude Code hook

Block risky installs automatically with a PreToolUse hook. Add this to .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "slopshield hook", "timeout": 10 }]
      }
    ]
  }
}

Now whenever the agent runs npm install …, slopshield checks the packages first. A high/critical package (e.g. a hallucinated name that doesn't exist) is denied, and the reason is fed back to the model so it can correct itself; a medium risk asks you to confirm; safe installs proceed silently. The threshold and an allowlist are read from package.json#slopshield.

The hook is best-effort defense-in-depth, and it fails open: anything it can't confidently parse is allowed rather than blocked. It resolves quotes and backslash escapes, but by design it does not resolve runtime shell indirection — command substitution ($(…), `…`) and variable expansion ($VAR) pass through unchecked — and it currently covers npm only (npx, yarn, and pnpm are on the roadmap). Pair it with the MCP server above for stronger coverage.

Development

npm test              # run the test suite (Node's built-in runner; needs Node 23.6+)
npm run test:coverage # run with ≥80% coverage thresholds
npm run typecheck     # tsc --noEmit
npm run build         # bundle to dist/cli.js
npm run validate      # measure recall / false-positive rate over the corpus (needs network)
npm run build:data    # regenerate src/data/popular-packages.json (needs network)

See CONTRIBUTING.md for the full guide and SECURITY.md to report a vulnerability.

License

MIT