Built by Blvkware
pkgguard is an open-source security tool and API that verifies npm, PyPI, and crates.io package names before installation, to catch LLM-hallucinated dependencies and slopsquatting supply-chain attacks. It detects the conflation attack pattern — where an AI blends two real package names into a third that never existed — which typosquatting scanners structurally cannot catch. Measured at 1.0% false positives with 7/7 threat recall against live registry data.
pip install -e . && pkgguard check -e npm react-codeshift
# BLOCK react-codeshift [npm] risk=100- What is slopsquatting?
- What problem does pkgguard solve?
- Why can't existing scanners catch this?
- How accurate is pkgguard?
- Installation
- Usage
- How the risk scoring works
- FAQ
- Limitations
- License
Slopsquatting is a software supply-chain attack in which an attacker registers a package name that AI coding assistants are known to hallucinate. When a developer or autonomous agent runs the suggested install command, they download attacker-controlled code instead of hitting a "package not found" error.
It works because package hallucination is measurable and repeatable:
- A 2025 USENIX Security study of 16 models across 576,000 code samples found AI tools recommend nonexistent packages roughly 19.7% of the time.
- 43% of hallucinated names were reproduced identically across repeated runs of the same prompt — making them a predictable target list.
- A 2026 replication across five frontier models measured hallucination rates of 4.62%–6.10% — lower, but not retired.
- That replication identified 127 package names all five models invent identically.
Confirmed incidents include react-codeshift and unused-imports on npm, and
a hallucinated huggingface-cli install command that was copied into public
documentation and accumulated over 30,000 downloads.
Autonomous coding agents now run install commands themselves, removing the
human review step that used to catch fake package names. A developer glancing
at npm install some-package was an implicit checkpoint. An agent executing its
own generated output is not.
pkgguard restores that checkpoint programmatically. It sits between an AI agent's suggestion and your package manager, and answers one question: is this name real, and does it look like something an attacker planted?
Because hallucinated names are not misspellings, so edit-distance similarity checks score them as unrelated packages.
The dominant attack shape is conflation — an LLM blending two real packages into a third:
jscodeshift + react-codemod → react-codeshift
react-codeshift is eight or more edits from either parent. Every typosquat
heuristic reads it as an unrelated package and lets it through. It was
registered on npm in January 2026 after appearing in LLM-generated agent skills.
pkgguard's conflation detector is built for exactly this: it tokenizes the candidate name, checks whether each token traces back to a different real popular package, and confirms no real package contains the full combination.
An existence check alone does not protect you. By the time you look, the hallucinated name frequently does exist — because someone registered it. That is the entire attack.
Benchmarked against live registry data, not synthetic fixtures.
| Metric | Result |
|---|---|
False BLOCK on 200 real npm packages outside the popularity corpus |
1.0% |
Correctly ALLOWed |
96.0% |
| Threat recall (real slopsquats, conflations, typosquats) | 7/7 |
Both documented real-world slopsquats — react-codeshift and unused-imports —
score 100 and BLOCK.
An early version of the conflation detector benchmarked at 0% false positives. That test was worthless: it ran against packages that were in the popularity corpus, which short-circuit the check.
Re-run honestly against 800 real packages outside the corpus, the same
detector flagged 62.5% of legitimate packages. Names like
mock-redis-client and react-loading-hook are token blends too.
Two architectural corrections brought it to 1.0%:
-
Conflation is not a standalone signal. It is gated behind weak reputation and weighted so it cannot reach
BLOCKalone. Conflation plus brand-new plus single-version blocks. Conflation plus real release history does not. -
Typosquat detection measures adoption ratio, not spelling.
expresis 14 years old with a real repository and 22,468 monthly downloads — every age-and-history heuristic reads it as legitimate. Butexpresshas 529,873,075. Capturing 0.0042% of your namesake's traffic is the signature.
Reproduce both numbers yourself:
python scripts/benchmark.py --sample 200If you change any scoring logic, re-run it. A change that improves false positives at the cost of recall is not an improvement — report both or neither.
git clone https://github.com/rxslice/pkgguard.git
cd pkgguard
pip install -e .Requires Python 3.9+. No API key. No account. No proprietary data feed.
For the HTTP API: pip install -e ".[api]".
# check names directly
pkgguard check -e npm react-codeshift lodash express
# check what an AI agent is about to run
echo "npm install react-codeshift lodash" | pkgguard scan-command
# gate a build
pkgguard scan-manifest package.json
pkgguard scan-manifest requirements.txt
pkgguard scan-manifest Cargo.tomlExits 1 if anything is BLOCKed, so it drops straight into CI.
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. This is the signature of an LLM
hallucination-by-conflation, which edit-distance typosquat checks
do not detect.
- Only a single published version — no release history.
- Low adoption: 11 downloads in the last month.
> Do not install without verifying this is the package you intend.
uvicorn pkgguard.api:app --reload
# interactive docs: http://127.0.0.1:8000/docscurl -X POST http://127.0.0.1:8000/v1/verify \
-H "Content-Type: application/json" \
-d '{"names":["react-codeshift","express"],"ecosystem":"npm"}'{
"results": [
{ "name": "react-codeshift", "verdict": "BLOCK", "risk_score": 100, "exists": true },
{ "name": "express", "verdict": "ALLOW", "risk_score": 0, "exists": true }
],
"blocked": 1,
"allowed": 1,
"safe_to_proceed": false
}Agent frameworks can gate a tool call on the single safe_to_proceed field.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/v1/health |
Liveness + supported ecosystems |
GET |
/v1/verify/{ecosystem}/{name} |
Verify one package |
POST |
/v1/verify |
Verify a batch (up to 100) |
.github/workflows/pkgguard.yml fails the build on any BLOCK:
- name: Install pkgguard
run: pip install -e .
- name: Verify npm dependencies
run: pkgguard scan-manifest package.json| Signal | Weight | Notes |
|---|---|---|
| Package does not exist | +70 | An AI suggested a name that isn't real |
| On known-hallucination corpus | +60 | Documented in public research |
| Confirmed typosquat | +60 | Close spelling and under 1% of target's downloads |
| Conflation (weak reputation only) | +30 | Cannot reach BLOCK alone — by design |
| Age 30 days or less | +30 | |
| Unresolved typosquat (no download data) | +30 | Fails toward caution |
| Age 120 days or less | +15 | |
| Single published version | +15 | |
| Under 1,000 monthly downloads | +15 | |
| No source repository | +10 |
BLOCK at 60+ · REVIEW at 25+ · otherwise ALLOW
A registry failure never returns ALLOW — it returns REVIEW with the error
surfaced. Failing toward caution is deliberate.
Conflation and typosquat detection are only as good as the popularity index.
python scripts/refresh_corpus.py --ecosystem npm --limit 3000
python scripts/refresh_corpus.py --ecosystem pypi --limit 3000
python scripts/refresh_corpus.py --ecosystem crates --limit 1500Quarterly is plenty. Note that npm's search API is lossy — it omitted lodash,
jscodeshift, and react-codemod from an 11,000-name harvest — so
data/must_include.json is merged in unconditionally.
No. pkgguard verifies the name, before installation. Content scanning is a different layer — pair it with a tool that does that. pkgguard covers the pre-install window that content scanners largely do not.
npm, PyPI, and crates.io. npm and crates.io expose download counts, so adoption-ratio typosquat detection is strongest there. PyPI's JSON API does not expose downloads, so PyPI falls back to reputation heuristics and is weaker.
No. All three registries expose free, unauthenticated, public JSON APIs. That is deliberate — it keeps the tool free to run and free to self-host.
Partially. The popularity corpora ship with the repo, so conflation and typosquat matching work offline. Existence and reputation checks require registry access.
Because a nonexistent name is not permanently safe. Models reproduce the same hallucinations across runs, so an unclaimed hallucinated name is a standing target an attacker can register tomorrow.
Possibly, as REVIEW — not BLOCK. A genuinely new, low-adoption package that
blends common tokens looks structurally similar to a slopsquat. That is the
intended trade-off, not a bug. Established packages with real release history
are not flagged.
Yes, for internal use — including inside for-profit companies, in your CI/CD, and in internal developer platforms. A commercial license is required only to resell it, host it as a service, or embed it in a product you sell. See COMMERCIAL-LICENSE.md.
Those scan installed dependencies for malicious behavior. pkgguard analyzes the name before install, and specifically detects conflation — the blend pattern that similarity-based scanners structurally miss. Complementary, not a replacement.
Read these before relying on it.
- Conflation cannot distinguish a hallucination from a legitimate new package that blends common tokens. This is why it is gated behind reputation.
- The known-hallucination corpus holds only 3 entries, because it contains
only names with a citable public source. Do not pad it with guesses — a false
entry produces a confident, wrong
BLOCK. - Adoption-ratio confirmation needs download data, which PyPI does not provide.
- This is one layer of defense, not a complete supply-chain security program.
slopsquatting detection · AI package hallucination · LLM hallucinated dependencies · npm typosquatting scanner · PyPI supply chain security · dependency confusion · AI coding agent security · package name verification API · software supply chain attack prevention · conflation detection · CI/CD dependency gate
Business Source License 1.1 — free for internal and CI use, including at commercial companies. A commercial license is required to resell, host, or embed it. Converts to Apache 2.0 on 2030-09-05.
Built by Blvkware — solo-built developer and security tooling.