DEV Community

Noble Ronin
Noble Ronin

Posted on

AI Keeps Recommending Fake Packages. I Checked Which Ones Are Still Sitting Open.

AI Keeps Recommending Fake Packages. I Checked Which Ones Are Still Sitting Open.

I maintain a scraper that reads npm, PyPI and crates.io for a living — side
project, package-registry-scraper
on Apify. This week I wasn't debugging the scraper. I was trying to answer a
smaller, dumber question: when people say "AI keeps recommending packages
that don't exist," and security researchers have already written about the
specific fake names — are those names still sitting there, right now,
exactly as dangerous as the reports say?

The honest answer turned out to be "it depends which registry you ask, and
the reports are already a little out of date."

The three names I actually checked

Slopsquatting isn't new — the term describes an attacker registering a
package name that an LLM hallucinates, so that whoever's agent tries to
npm install or pip install it next gets the attacker's code instead of a

  1. Three concrete, named cases came up in my research:
  • unused-imports on npm — AI tools apparently hallucinate this instead of the real eslint-plugin-unused-imports, and it was reportedly weaponized.
  • react-codeshift on npm — hallucinated, then defensively registered by a security researcher before an attacker could get to it.
  • huggingface-cli on PyPI — the original 2023/2024 proof-of-concept: a researcher uploaded an empty package under a name ChatGPT kept inventing, and real developers installed it thousands of times.

None of that is new reporting. What I wanted to know was the current state —
not what a blog post said six or twelve months ago, but what the registry's
own API says if you ask it today.

npm already cleaned one of them up — and the cleanup itself is interesting

curl -s https://registry.npmjs.org/unused-imports | python3 -m json.tool
Enter fullscreen mode Exit fullscreen mode

Right now, unused-imports resolves to version 0.0.1-security, described
as a "security holding package," with maintainers: []. npm has clearly
acted on it. But here's the part that surprised me: the versions{} object
in that response has exactly one entry — the holding package. The real
1.0.0 and 9.9.0 releases are gone from it entirely. Yet the time{}
object still remembers them: 1.0.0 published 2025-03-17, 9.9.0 published
2025-09-15, the security hold applied 2025-10-27. So the malicious package
lived for roughly seven months before npm acted, and when npm finally did
act, it erased the version payloads but left a paper trail of timestamps for
versions that no longer resolve to anything.

That's one source of the discrepancy with what I'd read going in: a report I
found said this package was "still live, pulling ~233 weekly downloads, as
of early February 2026." Checked live, right now, it's been a dead security
placeholder since October 2025 — months before that report's own date. I'm
not assuming the report was wrong when it was written; I'm saying don't
trust a stat like that without re-checking it, because the window it
describes can already be closed by the time you read about it.

One is a confirmed, deliberate decoy

curl -s https://registry.npmjs.org/react-codeshift | python3 -m json.tool
Enter fullscreen mode Exit fullscreen mode

This one matched the reporting exactly: real package, one version, the
maintainer is debugducky@ceriksen.com — Charlie Eriksen is a named security
researcher at Aikido Security — description "Placeholder to prevent
dependency confusion," homepage pointed at Aikido's own threat-intel page.
He apparently found AI coding agents still trying to install it daily after
it had spread through 237 forked repos, and grabbed the name himself rather
than wait for someone worse to. Confirmed, live, no surprises.

And one is just... open. Right now.

This is the one that actually stopped me. huggingface-cli was the package
from the original slopsquatting demonstration — the one that kicked off
the whole research area, with a researcher's empty decoy package reportedly
pulling five-figure download counts over a few months back in 2023-2024.

curl -s https://pypi.org/pypi/huggingface-cli/json
# {"message": "Not Found"}

curl -s https://pypi.org/simple/huggingface-cli/
# 404
Enter fullscreen mode Exit fullscreen mode

Both PyPI's JSON API and its plain package index say the same thing: nobody
holds this name. I checked the underscore variant too (huggingface_cli),
in case PyPI had normalized it differently — also 404. The most famous
hallucinated-package proof-of-concept in the field is sitting on an open
registry, available to literally anyone who registers it next, including
someone with worse intentions than the original researcher had.

npm's answer to "a hallucinated name got attention" is a tombstone nobody
can overwrite. PyPI's answer, at least for this one name, was apparently to
let the decoy package lapse and the name go back in the pool. That's not a
bug report about PyPI generally — I only checked one name — but it's a
concrete, structural difference between how the two registries leave a
known-dangerous name after the dust settles, and it's checkable by anyone
with curl and two minutes.

Where I could be wrong

I checked three names, not a representative sample — this is not "PyPI is
worse than npm at handling this," it's "these two specific names currently
look different, and the difference is worth knowing if you're the one
deciding whether to feel safe." I also can't tell you why huggingface-cli
was freed on PyPI — expired hold, policy decision, the original researcher
abandoning it, or something else. PyPI's public API doesn't expose a
takedown history the way npm's time{} ghost-timestamps do, so I genuinely
don't have a way to check that live. And the "233 weekly downloads" figure I
contradicted is itself secondhand — I didn't verify it was ever true, only
that it isn't true of the current state.

I keep the full three-registry check — endpoints, what a security hold looks
like on each one, and how to script this yourself before you install
whatever your AI assistant just suggested — in
noble-ronin/package-hallucination-check.

If your AI assistant has ever suggested installing a package you'd never
heard of — did you check whether it actually existed before you ran the
install, or after something went wrong?

Top comments (0)