| name | dep-verify-guard |
| description | Blocks hallucinated, typosquatted/slopsquatted, and unnecessary dependencies from being installed by verifying each new package against the real registry (npm/PyPI/crates) before it's added. Best used reactively before adding, importing, or installing any dependency. Use when the user says "install X", "add a package for", "npm/pip/cargo add", "import", or when a coding agent introduces a new third-party import. DO NOT USE for secret exposure (use no-secret-leak-guard) or general diff review (use clean-diff-guard); this guard is specifically about dependency existence, typosquatting, and necessity. |
dep-verify-guard
Never install a package on faith. LLMs predictably hallucinate
plausible-sounding package names, and attackers pre-register those exact
names on public registries so the hallucination becomes a working,
malicious install the moment an agent runs npm install <name>. This
guard makes "does this package actually exist, and do we actually need
it" a checked step, not an assumption.
Research on this failure mode (CSA, Unit42, and related slopsquatting
studies) found that LLM code generation hallucinates non-existent package
names in a meaningful fraction of dependency-adding requests, and that a
large fraction recur (reported in 2025–2026 slopsquatting research) across
repeated runs of the same prompt — stable enough for an attacker to
pre-register the exact name and wait. react-codeshift is a plausible
example of the pattern: a name an LLM could plausibly produce by
conflating two real packages (jscodeshift + react-codemod), but it does
not exist as a real published package. This guard exists to catch that
pattern before npm install runs, not after.
When to use — three modes
- Guard-pass (default). Right before running
npm install / pip install / cargo add / yarn add / pnpm add, or before writing an
import/require statement for a package not already in the
manifest/lockfile: verify the package per the Procedure below. This is
the mode that fires on trigger phrases like "install X," "add a package
for," "npm/pip/cargo add," or "import."
- Live. While actively writing code and reaching for a third-party
helper mid-task (e.g., typing
import { chunk } from 'lodash.chunk'):
pause at the import line itself, not at a later review pass. Verify the
name is real and actually needed before the line is finalized, the same
way you'd check a function signature before calling it.
- Review. When asked to review a diff, PR, or lockfile change that
adds dependencies: treat every new entry in
package.json/requirements.txt/Cargo.toml and its corresponding
lockfile as something to verify, not something to wave through because
it's already there. A dependency added by a previous agent turn or a
teammate gets the same scrutiny as one you're about to add yourself.
What this guard blocks
- Unverified existence. For EVERY new import/package, verify it
exists on the real registry (npm, PyPI, crates.io, etc.) using
available tools — a registry lookup, the package manager's own
search/info/view command, or a web fetch of the registry's public
API. Never assume a plausible-sounding name is real because it "sounds
like" a package that should exist. See
references/registry-verification.md for the per-ecosystem commands.
- Typosquat / conflation near a popular package. Check whether the
requested name is a near-miss of, or a plausible mashup of, an
established popular package. List the closest real ones by name when
flagging this — e.g.
react-codeshift → the real packages are
jscodeshift and react-codemod; python-dateutil typo'd as
python-datetuil → the real package is python-dateutil. See
references/slopsquat-checklist.md for the common hallucinated-name
shapes (conflation, pluralization drift, scope-dropping,
version-suffix guessing).
- Suspicious-new or low-signal packages. Flag packages that are
brand-new (registered days to a few weeks ago), have zero or
near-zero weekly downloads, have a single maintainer with no other
published packages, or have had no release in years while claiming to
solve an actively-maintained problem — for human confirmation before
installing. A name existing on the registry is necessary but not
sufficient; a squat is also "real" the moment it's registered.
- Unnecessary additions. Before adding any package, check whether
the standard library or an already-installed dependency already
covers the need. Do not add a package the task didn't actually
require — every added dependency is additional supply-chain surface,
install-time code execution risk, and maintenance burden, regardless
of how small it is.
- Unpinned / unrecorded resolution. Once a package is verified and
genuinely needed, record the exact resolved version (not a loose
^/* range invented from memory) in the manifest and confirm it
lands correctly in the lockfile. Note explicitly that most package
managers run arbitrary install-time scripts (postinstall, build
hooks) for every transitive dependency — a verified top-level package
can still pull in an unverified, unreviewed dependency tree.
- Can't-verify means ask, not install. If the available tools cannot
confirm a package's existence (no network access, registry lookup
fails, ambiguous name with no single best match), say so explicitly
and ask the user before installing. Do not fall back to "it's
probably fine" — the entire point of this guard is that "probably
fine" is exactly how slopsquats get installed.
Procedure — guard-pass steps
- Enumerate the new dependencies. Diff the manifest (
package.json
dependencies/devDependencies, requirements.txt/pyproject.toml,
Cargo.toml) and/or lockfile against what was there before this
change. List every package that is new, not already present.
- Verify each one exists, using the ecosystem's own tooling (
npm view <name>, pip index versions <name> / PyPI JSON API, cargo search <name>) per references/registry-verification.md. Record
what came back: exists / does not exist / ambiguous.
- Check for typosquat/conflation against well-known packages solving
the same stated problem, using
references/slopsquat-checklist.md's
heuristics. If the name is a near-miss or a mashup, name the real
package(s) it's most likely confused with.
- Check age, downloads, and maintenance signal for anything that
exists but looks new or thin. Note the registered date, weekly
download count (if available), and last-release date in the report.
- Ask "did the task actually need this?" Check the standard library
and the existing dependency tree first. If an existing capability
covers it, recommend that instead and do not add the package.
- Report per package: exists (Y/N) · age/downloads/maintenance
signal (if thin, flagged) · typosquat risk (named alternatives if
any) · necessity call (needed / stdlib-or-existing-dep-covers-it) ·
resolved version to pin.
- If everything checks out, proceed with the install/import and
record the resolved version. If anything is unverified, hallucinated,
squatted, thin, or unnecessary, stop and surface it before installing
— do not install first and mention concerns after.
- Emit the guard footer (see Output) as the last line of the
response.
Output
Emit this verbatim as the last line of any response where a dependency
was added, considered, or reviewed:
proofguard:dep-verify-guard — <PASS | FIX-REQUIRED | WAIVED(reason)> · Triggered: <what fired it> · Fixed: <n> · Verified: <what was checked — registry lookup, typosquat check, necessity> · Remaining gap: <what's unchecked>
PASS — every new dependency was confirmed to exist, isn't a
typosquat/conflation of a real package, isn't suspiciously new/thin
without disclosure, and is actually needed (stdlib/existing deps don't
already cover it).
FIX-REQUIRED — a hallucinated, typosquatted, unverifiable, or
unnecessary package was about to be installed and has not yet been
resolved (swapped for the real package, dropped in favor of stdlib, or
held for human confirmation).
WAIVED(reason) — the user, as the actual principal, explicitly
accepted a flagged risk (e.g. "yes, install the brand-new package
anyway, I trust the author") with a stated reason.
References
references/slopsquat-checklist.md — the slopsquatting threat model,
the react-codeshift case in detail, and the common shapes
hallucinated package names take (conflation, pluralization drift,
scope-dropping, plausible-suffix guessing).
references/registry-verification.md — exact per-ecosystem commands
for verifying existence, age, and download/maintenance signal (npm,
PyPI, crates.io), plus the stdlib-first rule.
What this guard does NOT do
It is not a full SCA (software composition analysis) or vulnerability
scanner — it does not check known-CVE databases, license compatibility,
or dependency-tree-wide risk scoring. For that, recommend npm audit,
osv-scanner, or Socket as a follow-up. This guard targets the failure
mode vulnerability databases structurally cannot catch: a hallucinated or
freshly-squatted package name has no CVE history yet, because nothing has
been reported against it — the risk is entirely in whether the name is
real, correctly typed, and actually needed, which is exactly the window
before install where vuln scanners have nothing to say.