cd /news/ai-safety/ai-keeps-recommending-fake-packages-… Β· home β€Ί topics β€Ί ai-safety β€Ί article
[ARTICLE Β· art-149514] src=dev.to β†— pub= topic=ai-safety verified=true sentiment=Β· neutral

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

A developer who maintains the package-registry-scraper on Apify re-checked the live npm and PyPI registries to verify whether previously reported AI-hallucinated package names are still exploitable. The npm package unused-imports has been a security holding package since October 2025, roughly seven months after its malicious versions were published, while react-codeshift remains a researcher-registered placeholder and the original PyPI proof-of-concept huggingface-cli now returns 404 on both the JSON API and simple index. The findings show that published slopsquatting reports can be stale by the time they are read.

by read5 min views4 publishedOct 12, 2026

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."

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

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 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.

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

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.

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

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.

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

curl -s https://pypi.org/simple/huggingface-cli/

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.

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?

── more in #ai-safety 4 stories Β· sorted by recency
── more on @npm 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/ai-keeps-recommendin…] indexed:0 read:5min 2026-10-12 Β· β€”