Slopsquatting: The Hallucinated Package Problem in AI Code

Written By
SprintX Team
AI & Product Engineering
July 29, 2026
6 min read

AI models invent package names; attackers register them and wait. Here is the mechanics of the attack, how to find hallucinated dependencies, and how to prevent them.
Typosquatting has been around forever: register a package name one keystroke away from a popular one and wait for fat fingers. It works, but slowly, and only on the humans who mistype.
Slopsquatting is the version that scales. Language models do not mistype — they confabulate. Ask for a library that does a specific thing and a model will sometimes produce a plausible, well-named, entirely fictional package, with a confident import statement and usage example to match. The Cloud Security Alliance found that roughly 19.7% of 2.23 million AI-generated code samples referenced package names that do not exist.
Here is the part that turns a curiosity into an attack: models hallucinate the same names repeatedly. An attacker does not have to guess. They can prompt the popular models a few thousand times, collect the fictional names that come back more than once, and register them.
How the attack works
The chain is short, which is what makes it effective.
- Harvest. Run a model across a large set of realistic coding prompts and log every package it imports that does not resolve in the registry.
- Filter. Keep the names that recur. Recurrence means the next developer asking a similar question gets the same suggestion.
- Register. Publish a package under that exact name. Registries are open by design; nobody has to approve it.
- Wait. Somewhere, a developer or an autonomous agent asks the same question, receives the same import, and runs the install command.
- Execute. In many ecosystems, installation alone runs code — npm lifecycle scripts, Python setup logic. The payload does not need your app to call the library. It runs on install, on a developer machine or in CI, with whatever credentials that environment holds.
Step five is where people underestimate the blast radius. A CI runner holds deployment credentials, registry tokens, and cloud access — a far better target than the application itself.
Why models invent package names
Three causes, and they compound.
Naming is predictable. Package names follow strong conventions. A model that has seen thousands of names in the form of a framework prefix plus a function suffix will generate new ones in the same shape, and they will sound correct because they follow the same rules the real ones do.
The registry is not consulted. Unless the tool has been wired to check, generation happens without any lookup. There is no step where the model verifies that the thing it just named exists.
Deprecation reads as existence. Packages that were renamed, merged, or deleted after training still appear throughout the training data. The model has genuinely seen them; they are simply no longer there — which leaves a name that is unclaimed and reputable-looking. That combination is exactly what an attacker wants.
Agentic coding sharpens all of this. When a coding agent installs its own dependencies mid-session to fix its own import error, nobody sees the package name at all. It appears in a lockfile, and lockfiles are the file everyone skips in review.
Finding hallucinated dependencies in code you already have
Do this on any AI-built project that has been running for a while. It takes under an hour.
Diff installed against declared. Compare what is in your lockfile to what your manifest declares and to what your source actually imports. Three-way mismatches are where the interesting stuff hides.
Look up every direct dependency by hand. For each one, check that the registry page exists, that it has a repository link, and that the repository is real. This is boring and it is the entire detection method — a package that resolves is not the same as a package that is legitimate.
Sort by publish date and download count. A recently published dependency with very few downloads, sitting in an agent-built project, deserves an explanation. Real packages have history and obvious provenance.
Read the install scripts. Any postinstall or preinstall hook needs justification. Native modules legitimately have them; a date-formatting helper does not.
| Signal | What it usually means | What to do |
|---|---|---|
| Package not found on install | Pure hallucination, not yet weaponized | Remove the import, find the real library |
| Exists, published within weeks, near-zero downloads | Possible slopsquat | Do not install; verify the repository and maintainer |
| Exists, no source repository linked | Unverifiable provenance | Treat as untrusted, replace |
| Has postinstall script, no native code | High risk | Block, install with scripts disabled, inspect |
| In lockfile, not in manifest or imports | Agent added it, nobody kept it | Remove and rebuild the lockfile |
If a suspicious package was ever installed on a machine with credentials, treat it as a credential incident, not a dependency cleanup. Rotate everything that machine could reach. The broader cleanup process is covered in auditing dependencies in an AI-written codebase.
Prevention that survives agentic coding
Telling developers to check every suggestion does not work, because the agent installs packages without showing anyone. The controls have to sit in the pipeline.
- Commit the lockfile and install from it. Use the reproducible install command in CI so builds cannot silently pull something new.
- Disable install scripts by default. Both npm and pip support installing without running lifecycle hooks. Allow them for the small set of packages that genuinely need native builds, and only those.
- Put a proxy or private registry in front of the public one. This gives you an allowlist, a quarantine period for newly published packages, and a record of exactly what entered your build.
- Fail CI on new direct dependencies. Not on all changes — just on additions to the direct dependency list, which should be a human decision. Pair this with the review gates in a CI/CD setup for a vibe-coded app.
- Never install from AI output on a machine with production credentials. Do it in a container with no ambient access. Developer laptops are the softest target in most companies.
The intent behind all of this is one rule: adding a dependency should be a deliberate act by a person, even when a machine wrote the code that needs it.
Frequently asked questions
Does this only affect npm and PyPI? Those are the loudest cases because both registries are open, both are heavily represented in training data, and both can execute code at install time. The same mechanism applies anywhere name-based resolution meets open publishing — Go modules, crates, Ruby gems, container image tags. Ecosystems that require signed publishing or reserve namespaces are harder to attack, not immune.
If the install failed with a 404, am I fine? For now. A failed install means the name was hallucinated but not yet registered, which is a temporary state. Note the name, remove the import, and do not retry the install later on the assumption that it was a network blip.
Can I just ask the model to verify its own package suggestions? Only if the tool actually performs a registry lookup — some agents now do, and that genuinely helps. A model asked to confirm from memory will confirm, confidently, including for packages that have never existed. Verification has to touch the registry, and that check belongs in your pipeline, not in a prompt. It is one of the standard checks in an AI code audit.
If your project was built by an agent that installed its own dependencies, nobody has read that list, and it deploys from CI with real credentials, that is a supply chain exposure with a clear fix. SprintX audits AI-generated dependency trees, verifies provenance package by package, and puts the controls in your pipeline so it stops happening. Send us your lockfile.


