AI Security

What Is Slopsquatting? How AI-Invented Packages End Up in Real Codebases

Attackers register the package names AI assistants invent. What the research measured, how to find a hallucinated dependency already sitting in your repo, and why a one-time cleanup is not a control.

Webcuris Research

Security Engineering

·4 min read

A terminal row: npm install of a struck-through hallucinated package name, annotated 30,000 installs of an empty name

Slopsquatting is a supply-chain attack aimed at the package names AI coding assistants invent. Language models routinely recommend installing packages that do not exist. Attackers register those names on npm, PyPI and other public registries — and wait. The next developer whose assistant hallucinates the same name, and who runs the install command it helpfully formats for copying, pulls the attacker's code into their build. The term was coined by security researcher Seth Larson, by analogy with typosquatting: instead of betting on human typos, the attacker bets on machine hallucinations.

Four-step flow: an assistant suggests a package name, the package does not exist, an attacker registers the name, your build runs its scripts with CI secrets
From hallucination to your build, in four steps — and the check that interrupts it.

How big is this, measured

This is one of the few new attack classes that arrived with real numbers attached. A study presented at USENIX Security 2025 tested sixteen code-generating models across 576,000 samples and found that roughly one in five generated code samples referenced packages that do not exist — over 205,000 unique hallucinated names across the runs (the paper).

And the names get used. In one widely-reported experiment, a researcher registered an empty package under huggingface-cli — a name models kept inventing for Hugging Face's real tool, which actually installs as huggingface_hub. With no code, no README, and no promotion, it was downloaded more than 30,000 times in three months (recounted by Trend Micro). Every one of those installs would have executed a hostile postinstall script if the package had carried one.

Hallucination patternWhat it looks likeWhy it lands
Mashup of real nameshuggingface-cli, openai-toolsSounds exactly like something the vendor would publish
Near-variant of a real packagepython-dotenv vs dotenv-pythonIndistinguishable from memory; both orderings feel right
Pure fabricationA plausible name for a function the model wishes existedThe model presents it with the same confidence as a real one
The three shapes the USENIX study found. None of them look wrong in a code review.

Why this works so well

Hallucinations are not random noise. The same prompts reproduce the same invented names across sessions and even across models — the study found a large share of hallucinated names recurred consistently. That repeatability is the entire business model: an attacker registers a name once, and every future developer who asks a similar question becomes a potential install. Add the delivery mechanism — an authoritative-sounding answer with a ready-to-paste npm install line — and the usual moment of skepticism never happens.

How to find one already in your codebase

There are two shapes to look for, and they carry different levels of alarm.

An import with no manifest entry (a phantom dependency): code imports a package that appears in no package.json, requirements.txt or lockfile. It arrived by paste, works by accident — through a transitive dependency, or a globally installed tool — and nobody ever vetted it.

A dependency that 404s on its public registry: the name your code depends on is not published at all. This is the alarming one — the name is sitting unclaimed, or worse, was claimed after your code started referencing it.

You can check any single suspect by hand:

does this package actually exist?bash
# npm — a 404 here means the name your code references is claimable by anyone
npm view some-package name

# PyPI
pip index versions some-package

# and is it actually declared, or just working by accident?
npm ls some-package

By hand does not scale to a real repository, which is why this check is part of Webcuris's local repository scan — the same one that hunts committed secrets. It walks your imports, compares them against every manifest, and then asks the registry. An import that 404s on the public registry is flagged at high severity with the registry response as evidence; a real-but-undeclared package is flagged as a phantom dependency. The scan runs on your machine — your source never leaves it.

If you find one

  1. Stop installs first. If the name is unpublished, any npm install between now and the fix is a race against whoever registers it.
  2. Check what it did. If a package by that name was installed, read its postinstall scripts and network calls before deciding anything else — that is where the payload lives.
  3. Find out when it arrived. git log -S on the import and the lockfile tells you which change introduced it, which usually tells you how.
  4. Rotate what the build could see. A hostile install script runs with your CI's credentials. Treat every secret in that environment as exposed until proven otherwise.
  5. Replace it with the real thing — the package the AI was reaching for usually exists under a different name.

Preventing the next one

  • Treat AI-suggested installs as untrusted input. Before installing, check the package's age, download count and repository link — a week-old package with no source link answering a years-old problem is the tell.
  • Commit lockfiles and install from them (npm ci, pip install -r with hashes) so a name resolves the same way twice.
  • Run installs with scripts disabled in CI (npm ci --ignore-scripts) where your stack allows it — it removes the most common payload vehicle.
  • Scan on every change, not once. Every AI session can re-hallucinate. A cleanup is a snapshot; only a check that runs when code changes is a control.

Get the next one

One email when a new article goes out. No newsletter, no drip sequence, no sales follow-up.

Unsubscribe in one click. We never sell or share the address.

Keep reading

Contact

Talk to us.

Questions about what the engine checks, whether it fits your estate, or what it deliberately refuses to do. A person reads every message.

  1. 01You writePlain form, no qualifying call, no obligation. The marketing checkbox is optional and unticked.
  2. 02A person reads itMessages land with the team, not a queue-bot. Nothing is auto-replied.
  3. 03You get an answerTo the address you gave — including “this product is not the right fit”, when that is the honest answer.
Reporting a vulnerability?
Read the disclosure policy first — it tells you what is in scope and what to expect.
New messagereplies go to your email

We reply to this address, so a disposable one will not reach you.

+91

0 / 4000