hallucheck
v0.3.0
Published
Catch AI hallucinations before they ship: fake packages AND invented methods that pass the linter and fail at runtime. npm + PyPI. Zero dependencies.
Downloads
724
Maintainers
Readme
hallucheck
AI invents package names. Attackers register them. You install them.
LLMs suggest packages that don't exist 19.7% of the time (576k-sample study) — and 43% of those fake names repeat on every run, which makes them predictable targets. Over 205,000 phantom names have been catalogued, and malicious packages exploiting this have racked up tens of thousands of downloads.
This is called slopsquatting. But there's a second, more common failure: the package is real and the method is invented — client.fetchDataV2() where only fetchData() exists. Those pass the linter and blow up at runtime.
hallucheck catches both.
npx hallucheck # scan the current directory
npx hallucheck ./my-app # scan another path
npx hallucheck --json # structured output for CITwo passes, one command:
- Dependencies — reads
package.json,requirements.txt,pyproject.toml(PEP 621 + Poetry) and checks every name against the live registry. - Code — parses your JS/TS imports and verifies every method you call actually exists on the package you installed.
Exits 1 on findings, so it fails your pipeline instead of shipping broken code.
Verdicts
| | Meaning | |---|---| | 🔴 SEIZED | npm took this name over for abuse/malware — the real package does not exist | | 🔴 NOT FOUND | not in the registry at all; the AI made it up | | 🟠 SUSPICIOUS | recently registered, single version, no repository, almost no downloads | | 🟡 WARN | one isolated signal, probably fine | | 🟢 OK | established package |
It also catches conflation — when a model fuses or shortens two real package names into a third one that doesn't exist.
A real example
🔴 SEIZED unused-imports
└─ npm SEIZED this name for abuse/malware — the real package does not exist
└─ still gets 436 downloads/week from people trusting an AI suggestion
🟢 OK eslint-plugin-unused-importsunused-imports is a well-documented hallucination of eslint-plugin-unused-imports. npm had to seize the name. It still receives hundreds of installs every week — that is the attack, live, right now.
Invented methods
🔴 src/app.js:3
_.chunkArray — "chunkArray" does not exist on "lodash"
└─ did you mean: chunk?LLMs hallucinate API calls at 5.2% (commercial models) to 21.7% (open models) — 576k generations across 16 models. Type checkers miss it when types are loose or absent; linters miss it entirely.
Verification is against the package actually installed in your node_modules, not a database — so it is correct for your exact version. If a package can't be resolved with confidence, hallucheck stays silent rather than guessing.
Note: reading a package's exports requires loading it, the same way your app does at startup. hallucheck only loads packages you already installed.
Precision
Run against a production React app — 23 dependencies and 244 source files, 134 imported members verified: 0 false positives, 4.8s. A scanner that screams at everything gets uninstalled — this one stays quiet.
Handles scoped packages, malformed manifests, and missing files without crashing.
Zero dependencies
Auditing your supply chain shouldn't add to your supply chain. hallucheck is one file, Node 18+, no node_modules.
MIT.
