Skip to main content
Glama
rayan1810

pkgbouncer

by rayan1810

pkgbouncer

npm CI license node

An install gate for AI coding agents. pkgbouncer sits between Claude Code (or any MCP-capable agent) and the package registries. Before a package is installed it checks the name and version against public malware and advisory feeds and blocks the install if the package is known-malicious, does not exist (hallucinated or slopsquatted), or looks like a typo of a popular package. It warns on releases younger than a few days, high-severity advisories, and install scripts. After an install it diffs the lockfile and flags anything risky that came in transitively. When it blocks, it tells the agent which version is safe so the agent can self-correct.

Covers npm, PyPI, crates.io, and Go.

pkgbouncer needs no account and no API key. It uses the free public OSV.dev database and the package registries, and nothing leaves your machine except package names.

Is it a tool, a hook, or an MCP server?

All three, over one rule engine. They differ in how much they can enforce:

Form

How it runs

Enforcement

Hook

Claude Code calls it automatically before and after every shell command

Enforced. The agent cannot skip it. This is the install gate.

MCP server

The agent can call it to check a package before editing a manifest

Advisory. The agent decides whether to ask.

CLI

You or CI run pkgbouncer check and pkgbouncer scan

Exit code 1 on a blocked package

Use the hook for protection and add the MCP server if you want the agent to check proactively.

Related MCP server: depscope-mcp

How it compares

Several tools guard installs. They differ in where they sit:

  • Socket Firewall, Aikido Safe Chain, and similar wrappers sit in front of the package manager. They protect a person typing the command, and can cover an agent only if its shell uses the wrapper.

  • Dependabot, Snyk, and similar scanners run on a schedule or in CI, after a package is already in your repository.

  • attach-guard is a Claude Code plugin that also uses a pre-install hook. It scores packages through Socket.dev and needs a Socket API token.

  • pkgbouncer is a Claude Code hook plus an MCP server and CLI that decides locally from public feeds. It covers bare installs and the post-install lockfile diff, and it requires no account.

If you already run one of these, pkgbouncer adds the agent-side gate. They do not conflict.

30-second install

npm install -g pkgbouncer

# Claude Code: adds PreToolUse + PostToolUse hooks on Bash and PowerShell to ~/.claude/settings.json
pkgbouncer install claude-code

From then on, in every new Claude Code session:

  • Named installs are gated. npm i, pnpm add, yarn add, bun add, npx, pip install, uv add, poetry add, pipx install, cargo add, cargo install, go get, go install. A blocked install returns the reason and a suggested safe version to the model.

  • Bare installs are gated. On npm install, npm ci, pnpm install, yarn, or bun install, every package.json dependency the lockfile does not yet satisfy is checked first. This is the "agent edited package.json, then ran npm install" path.

  • Transitive hits are caught. Before any install the lockfile is snapshotted. After it, only the newly added packages are scanned against OSV, and malware or critical advisories are reported back to the model with removal instructions. Works for all four ecosystems.

Example of what the agent sees:

[pkgbouncer] BLOCKED lodahs@0.0.1-security
  - (known-malicious) lodahs@0.0.1-security is a known malicious package (MAL-2025-25502: Malicious code in lodahs (npm)).
  - (typosquat) lodahs looks like a typo of the popular package "lodash". Confirm you meant lodahs.
  -> No safe version found; pick a different package.
Install blocked by pkgbouncer. Use the suggested safe version or a different package, then retry.

Cursor: pkgbouncer install cursor writes a beforeShellExecution hook following Cursor's documented format. It has not been verified against a live Cursor install yet.

MCP server

The same checks are exposed as MCP tools so an agent can ask before it edits a manifest directly.

Claude Code:

claude mcp add pkgbouncer -- pkgbouncer mcp

Cursor (~/.cursor/mcp.json or .cursor/mcp.json):

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

Tool

Purpose

check_package

Allow / warn / deny for name[@version] in a given ecosystem, with reasons and a suggested safe version. The description tells the model to call it before any install.

scan_project

Scan every lockfile in a directory for known-malicious packages and critical advisories.

suggest_safe_version

Newest version with no malware, no critical advisory, and older than the policy minimum age.

CLI

pkgbouncer check lodash react@18 @types/node        # npm by default; exit 1 if any is blocked
pkgbouncer check pypi:requests==2.31.0 crates:serde@1 go:github.com/gin-gonic/gin@v1.9.1
pkgbouncer check --ecosystem PyPI requests numpy
pkgbouncer check --json axios                        # machine-readable verdicts
pkgbouncer scan ./my-project                         # all lockfiles in the dir, exit 1 on hits

Lockfiles understood: package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock, bun.lock, uv.lock, poetry.lock, requirements.txt (pinned lines only), Cargo.lock, go.sum.

Rules

Rule

Signal

Default

known-malicious

OSV record with a MAL- id for this version

deny

critical-advisory

OSV / GitHub / PyPA / Go advisory for this version

CRITICAL deny, HIGH warn

nonexistent

Package or version not on the registry (hint if it resembles a popular name)

deny

too-new

Published less than minAgeDays ago

warn (deny with strict)

typosquat

Edit distance 1 or 2 from a bundled popular name (npm, PyPI, crates)

warn

install-scripts

npm version declares preinstall / install / postinstall

warn

source-unavailable

OSV or registry unreachable

warn (deny with failClosed)

Policy

Put pkgbouncer.json in the project root, or ~/.pkgbouncer/policy.json for a user-wide default. All fields are optional.

{
  "minAgeDays": 3,
  "strict": false,
  "failClosed": false,
  "allow": ["@mycompany/*", "internal-tool"],
  "deny": ["event-stream@<4", "colors@>1.4.0"]
}
  • allow entries short-circuit every rule. deny entries always block.

  • Entries are name, name@semver-range, or @scope/*.

Environment variables: PKGBOUNCER_HOME (default ~/.pkgbouncer), PKGBOUNCER_CACHE_DIR, PKGBOUNCER_OSV_URL, PKGBOUNCER_NPM_REGISTRY, PKGBOUNCER_PYPI_URL, PKGBOUNCER_CRATES_URL, PKGBOUNCER_GOPROXY_URL.

What it does and does not catch

pkgbouncer is feed-based. It catches what has been reported to OSV.dev (which ingests the OpenSSF malicious-packages list, the GitHub Advisory Database, PyPA advisories, RustSec, and the Go vulnerability database) and what registry metadata reveals. Most malicious packages are classified within three days of publication, and the too-new rule buys you that window. It does not analyze package code and will not catch a brand-new compromise before anyone reports it.

Transitive dependencies are judged after the install, from the lockfile diff, not before. A malicious transitive package will land on disk once and be reported immediately; the agent is told to remove it. Pair pkgbouncer with --ignore-scripts (npm 12 does this by default) for defense in depth.

Results are cached under ~/.pkgbouncer/cache (advisories 1 hour, registry metadata 6 hours, misses 10 minutes). Lookups go to OSV and the registries only; nothing about your project leaves your machine except package names.

Exit codes

Command

0

1

2

check, scan

allow or warn

at least one deny

usage or no lockfile

hook claude-code

allow or warn

deny (blocks in PreToolUse; reports to the model in PostToolUse)

hook cursor

always; verdict is in stdout JSON

If pkgbouncer itself crashes inside a hook it exits 0 so the agent is never wedged by the gate.

Status

Version 0.1.0, early release. The Claude Code hook has been verified in live Claude Code sessions on Windows. The Cursor hook is written to Cursor's documented format but has not been tested in a live Cursor install. Bug reports and false positives are very welcome.

Contributing

Contributions are welcome. Read CONTRIBUTING.md for setup, the code map, and the ground rules. Please report vulnerabilities privately as described in SECURITY.md, and follow the Code of Conduct.

git clone https://github.com/rayan1810/pkgbouncer.git
cd pkgbouncer
npm install
npm run build
npm test          # vitest, no network needed
node dist/cli.js check lodash

Design and plans: docs/superpowers/specs/ and docs/superpowers/plans/. Release history is in CHANGELOG.md.

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Validates and checks packages across 19 ecosystems to prevent AI agents from installing hallucinated, deprecated, or malicious packages.
    14 npm
    AGPL 3.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI coding agents and CI to vet npm dependencies before they reach the lockfile, flagging hallucinated, slopsquatted, or otherwise risky packages with evidence-backed verdicts.
    3
    27 npm
    4
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables checking packages across npm, PyPI, Go, Maven, Cargo, NuGet, and RubyGems for existence, deprecation, known vulnerabilities, and license issues before installation, providing verdicts like does_not_exist, risky, verify, or ok.
    3
    1
    MIT