TL;DR
- AI editors invent package names that do not exist, and attackers register those exact names on npm and PyPI.
- Your dependency scanner reports zero findings on them, because a package published three weeks ago has no CVE history to match against.
- The fix is checking that a package has a past before you install it, not scanning it after.
I asked Cursor for a codemod tool last month. It gave me a confident install command and a five-line usage example. The package name looked right. It sounded like something that would exist.
It did exist. That was the problem.
Somebody had registered the name because they knew the model would keep inventing it. The whole class of attack got a name in July when researchers published on it: Aya Spira and colleagues in Ben Nassi's group at Tel Aviv University, with Stav Cohen at Technion and Ron Bitton at Intuit, called it HalluSquatting. Most developers know it as slopsquatting. Their finding was that assistants do not hallucinate randomly. Ask the same question enough times and the same wrong name comes back, in up to 85% of repository requests in their tests. That is not noise. That is a stable, predictable target an attacker can register once and wait on.
Aikido's Charlie Eriksen had already found one in the wild in January: react-codeshift, a package that started life as a hallucination and ended up referenced by 237 code projects.
The Vulnerable Code
The vulnerability is not in code the AI writes. It is the install line, and it looks completely normal.
# Cursor suggested this. It runs without a single warning.
npm install react-codeshift
{
"dependencies": {
"react-codeshift": "^1.0.0"
}
}
Nothing here trips a linter, a type checker, or a code review. npm install runs the package's install scripts before you have read a line of it. By the time you notice the dependency in your package.json, it has already executed on your machine.
Why This Keeps Happening
Models produce package names the same way they produce everything else: by predicting plausible tokens, not by checking a registry. A name like react-codeshift is exactly what a real package would be called, which is precisely why the model generates it and precisely why nobody reviewing the diff blinks.
The second half is the part people miss. Hallucinations are consistent. The same prompt pulls the same invented name out of the same model over and over, so an attacker does not have to guess. They query the assistant a few dozen times, collect the names it keeps making up, and register them. The model does the targeting for free.
And the agent loop closes the gap. A developer used to have to copy a name, search for it, and decide. An agent with terminal access reads the suggestion and runs it. There is no moment where a human looks at the string.
The Fix
Check that the package has a history before you install it. Five seconds of registry metadata beats any scan you run afterwards.
# Before installing anything an AI suggested
npm view react-codeshift time.created
# Errors out? The package does not exist. That is the good outcome.
# Created last month, 40 weekly downloads? That is the attack.
Turn off install scripts so a mistake is recoverable instead of instant:
npm config set ignore-scripts true
npm ci --ignore-scripts
Python has a stronger version of this, because pip can refuse anything whose hash you have not already vouched for:
# requirements.txt
requests==2.32.3 \
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
pip install --require-hashes -r requirements.txt
A hallucinated package cannot get into a hash-pinned file, because you would have had to record its hash yourself.
One thing that does not help as much as people assume: the lockfile. A lockfile faithfully records whatever you installed the first time, including the malicious thing. It stops drift, it does not stop the initial install.
FAQ
Q: Does a lockfile protect me from slopsquatting?
A: Only after the fact. It pins what you already installed, so it prevents the version changing later, but the first install of a hallucinated name is what compromises you and the lockfile records it faithfully.
Q: Why does my dependency scanner report the package as clean?
A: Because CVE databases are backward looking. A package registered three weeks ago to catch a hallucination has no CVE, no advisory, and no reported malware, so a scan that matches against known vulnerabilities returns nothing.
Q: How do I tell a hallucinated package from a real one?
A: Check its creation date and download history before installing. A genuine dependency your AI recommends will have years of releases and real download volume. A slopsquat will have weeks.
I want to be straight about the tooling here, including my own. I run SafeWeave as an MCP server inside Cursor and Claude Code, and its dependency scanner is a CVE matcher like everyone else's. It will not flag a package that was registered last week specifically because nothing is known about it yet. What it does catch is everything else the agent leaves behind in the same session - the hardcoded key, the unparameterized query, the missing auth check. For slopsquatting specifically, the registry-age check above is the control that works. Run it before the install, not after.
Top comments (0)