01 / Verify identity
Does the name exist in its registry? How old is it, how many versions, how many downloads, is there a source repository?
pkgguard checks npm, PyPI and crates.io names before your package manager runs them, and answers ALLOW, REVIEW or BLOCK with the reasons. It catches the names AI coding agents hallucinate, the slopsquats registered to exploit them, and typosquats that spelling checks miss.
Free and open source · CLI · HTTP API · MCP server · GitHub Action · Apache 2.0 · no account, no key
Python 3.9 or newer. It runs where your agent or CI runs, and asks the public registries directly.
pip install "git+https://github.com/rxslice/pkgguard-API.git" pkgguard check -e npm react-codeshift lodash BLOCK react-codeshift [npm] risk=100 - Name appears on the known-hallucination corpus. - Name appears to blend 2 real packages (jscodeshift, react) into a combination that does not exist. - Only a single published version, with no release history. - Low adoption: 22 downloads in the last month. - No source repository linked in the registry metadata. ALLOW lodash [npm] risk=0 - Established package with no risk signals. 2 checked | 1 blocked | 0 review | 1 allowed
Install it from GitHub, not from PyPI. pkgguard is not published on PyPI and the name there is unclaimed. An unclaimed name that people are told to install is exactly what slopsquatting exploits, so never run a bare pip install pkgguard. Pin a release by adding @v0.1.0 to the URL.
Slopsquatting is the supply-chain attack that follows: an attacker registers a name an AI is likely to hallucinate, and the install command brings it into your build. Autonomous agents now run those commands themselves, so the human who used to glance at them is gone. Typosquat scanners miss the common case, because an invented name that blends two real ones is not a misspelling of either.
Does the name exist in its registry? How old is it, how many versions, how many downloads, is there a source repository?
Combine age, documented hallucinations, conflation and typosquat signals into one decision, with every reason listed.
Enforce one boolean, safe_to_execute, in an agent, a CI job, an MCP host or an install wrapper. It fails closed.
Benchmarked on live registry data, not synthetic fixtures, and reproducible with one script in the repository.
false BLOCKs on 200 real npm packages outside the popularity corpus
of those legitimate packages ALLOWed outright, with 3.0% sent to REVIEW for a person to decide
real threats caught: slopsquats, conflations and typosquats, including react-codeshift and unused-imports
The first version of the conflation check scored 0% false positives, and that test was worthless: it ran on packages the popularity corpus short-circuits. Run honestly on 800 packages outside it, the same check flagged 62.5% of legitimate names. Two changes brought it to 1.0%: conflation can no longer block on its own, only alongside weak reputation, and typosquats are measured by a name's share of its namesake's downloads rather than by spelling.
python scripts/benchmark.py --sample 200Check names, check a command an agent wrote, or gate a whole manifest. Exits 1 on BLOCK.
pkgguard check -e pypi requests-oauth2-helper echo "npm install react-codeshift" | pkgguard scan-command pkgguard scan-manifest requirements.txt
Wrap the real command. It runs unchanged only when pkgguard allows it.
pkgguard-gate -- npm install react-codeshift pkgguard authorize "uv add requests"
Understands npm, yarn, pnpm, bun, pip, uv, poetry and cargo. Chaining, pipes, redirection and shapes it does not recognise go to REVIEW instead of being half-parsed.
One tool, authorize_install_command, over stdio for any MCP host. It returns the decision, safe_to_execute, the packages and the full assessment.
pkgguard-mcpFails the build on BLOCK and REVIEW and publishes findings to Code Scanning as SARIF.
- uses: rxslice/pkgguard-API/.github/actions/scan@main with: manifest: package.json
The same checks behind two endpoints, served by you, for a fleet of agents or a platform. There is no hosted pkgguard to sign up for: you run it, so your install decisions never leave your infrastructure.
pip install "pkgguard[api] @ git+https://github.com/rxslice/pkgguard-API.git" uvicorn pkgguard.api:app --port 8000 curl -X POST http://127.0.0.1:8000/v1/agent/authorize \ -H "Content-Type: application/json" \ -d '{"command":"npm install react-codeshift lodash"}' curl -X POST http://127.0.0.1:8000/v1/verify \ -H "Content-Type: application/json" \ -d '{"names":["react-codeshift","express"],"ecosystem":"npm"}' → { "blocked": 1, "allowed": 1, "safe_to_proceed": false, ... }
Interactive documentation is served at /docs. A single-name check is GET /v1/verify/npm/express.
BLOCK at 60 or more, REVIEW at 25 or more, otherwise ALLOW. A registry that cannot be reached never produces ALLOW: it produces REVIEW with the error shown.
| Signal | Points | Why |
|---|---|---|
| Package does not exist | +70 | An AI suggested a name that is not real |
| On the known-hallucination corpus | +60 | Documented in public research |
| Confirmed typosquat | +60 | Close spelling and under 1% of the target's downloads |
| Conflation, with weak reputation only | +30 | Cannot reach BLOCK alone, by design |
| 30 days old or less | +30 | |
| Typosquat that cannot be resolved | +30 | No download data, so it fails toward caution |
| 120 days old or less | +15 | |
| Single published version | +15 | |
| Under 1,000 monthly downloads | +15 | |
| No source repository | +10 |
For a hosted check that also carries a growing record of the names models keep inventing, see HALLUX, which folds pkgguard in.
Whether an npm, PyPI or crates.io name exists, how old it is, how many versions and downloads it has, whether it has a source repository, whether it is a documented hallucination, whether it blends two real package names, and whether it is a typosquat measured by its share of the real package's downloads. It combines those into ALLOW, REVIEW or BLOCK and lists the reasons.
No. It protects the decision before anything is installed. Pair it with a content or runtime scanner for defense in depth.
Yes. Apache 2.0, free for commercial use, with no account, no API key and no paid data feed.
It is not published on PyPI, and the name there is unclaimed. Installing it from its repository means you get this code, not whatever a stranger might register under the name.
Use the MCP server, the install wrapper, your own HTTP endpoint or the GitHub Action. Each returns an explicit decision and a safe_to_execute boolean, and each fails closed.
A brand-new package with one version and few downloads will usually get REVIEW, and BLOCK only if other signals pile up. Teams that want a human approval step instead of a hard stop for new packages can set --new-package-policy review; documented hallucinations and confirmed typosquats stay blocked.