PACKAGE GUARD
LLMs recommend package names that aren't real, and attackers register
those hallucinated names ("slopsquatting") so the next agent that suggests one installs
theirs. Package Guard is the one
call an agent makes before npm install: is this name registered, does OSV
know anything bad about it, and how new and how downloaded is it.
FreeDeterministic — no LLMOSV.dev + npm/PyPIHTTP + MCP
The "hallucinated package" check is a registry lookup. If npm or PyPI has no package
by that name you get likely_hallucination: true, which means exactly that and no more —
it can't separate an invented name from a typo or a rename, and a package that only exists in your
private registry will read as missing here.
| Endpoint | What it does |
|---|---|
/api/verify-package | The guard. Is the name registered (else likely_hallucination + npm "did you mean") · OSV vulns & malware · age and weekly-download signals · deprecated · license → a verdict |
/api/check-vulns | Known vulnerabilities + malware advisories for name@version (OSV) |
/api/package-info | latest · deprecated · license · repo · weekly downloads · age |
/api/audit-deps | A list of names, or the dependencies + devDependencies in a package.json, or a requirements.txt. Direct entries only, first 40 |
/api/typosquat-scan | Generate ASCII lookalike names + report which are registered |
check-vulns queries OSV.dev, which covers npm, PyPI, Go, crates.io, RubyGems, Maven
and NuGet. The vulnerability half of verify-package is the same OSV query.
Everything else needs a package registry, and lib/pkg.js speaks two: npm, and PyPI
when you pass ecosystem=pypi. That covers existence, downloads, age, deprecation,
license and the lookalike check. Suggestions and the confusable_with signal use npm's
search API, so they are npm only.
So verify-package, package-info, typosquat-scan and
audit-deps are npm and PyPI tools. Pass one of the other five and the name is still
resolved against npm, which gives you a wrong answer:
ecosystem=nuget&name=Newtonsoft.Json returns exists: false. Use
check-vulns for those five until I've fixed it.
It never reads package contents. No install scripts, no code, no tarballs. A malicious package
with no OSV advisory and healthy download numbers comes back safe.
vulnerabilities.checked: false (with count: null) means the OSV request
failed and nothing was checked; the verdict drops to caution rather than
safe. count: 0 means OSV answered and had nothing.
audit-deps has no such guard yet: if its batch OSV call fails, every package in that
report shows vulns: 0.
audit-deps reads manifests, not lockfiles, and does not resolve the dependency
tree — only the entries you send. A range is reduced to the digits in it, so ^4.17.20
is checked as 4.17.20.
typosquat-scan generates ASCII edits only: deletions, adjacent transpositions,
doubled letters, the swaps l/1, o/0,
rn/m, -/_, .→-,
i→l, s→z, and the name with every hyphen or
underscore dropped. Up to 20 variants. No Unicode homoglyphs.
{ "mcpServers": { "package-guard": { "command": "npx", "args": ["-y", "package-guard-mcp"] } } }
Or call the HTTP endpoints directly — GET, JSON out, CORS open.