Slopsquatting: The Ghosts Your AI Installs for You
You ask your assistant for a snippet to parse an awkward date format. It hands you three clean lines, an import, and a helpful little note: "don't forget to install the lib." You copy, you pip install, you npm install, it works, you move on. The reflex of a dev in a hurry.
Except that package? Your AI just made it up. It didn't exist last week. It only exists because an attacker also read what the models hallucinate — and got there first.
That's slopsquatting: a supply-chain attack that no longer targets your code, but the imagination of the machine writing it for you. And the worst part is that it's predictable. Which makes it weaponizable.
What "hallucinating a package" actually means
An LLM doesn't know the list of packages that exist on PyPI or npm. It knows patterns. When you ask it for a feature, it generates a dependency name that sounds right: python-dateutils instead of python-dateutil, requests-oauth instead of requests-oauthlib, a fast-json-parser that nobody ever published. The shape is perfect. The substance is empty air.
In real life you usually catch it instantly: the install fails, "package not found," you fix it. No drama. The problem isn't the isolated hallucination — it's what happens when that ghost name actually exists.
Because between the moment the model invents a name and the moment you install it, there's a window. And in that window, someone can register the package.
Why it's reproducible (and why that changes everything)
The thing that makes this attack serious: package hallucinations aren't random noise. They're recurrent. The same model, on similar prompts, tends to reinvent the same fake name. An LLM's error distribution is stable — it leans toward the same naming conventions, the same analogies, the same "surely it's called this."
Put yourself in the attacker's head for a second. You don't have to guess. You mass-generate plausible coding requests, you collect the dependency names the models spit out, you filter for the ones that don't yet exist on the public registry, and you look at which ones come back most often. That gives you a list of recurring ghost names — empty slots that thousands of developers will, statistically, try to fill.
All that's left is to publish a package under that name. With the little postinstall that exfiltrates your environment variables, or a setup.py that phones home. You didn't breach a server. You just occupied a gap the AI was going to point developers straight into.
It's typosquatting, but the attacker no longer needs to bet on your typos. They bet on the model's mistakes — and those, they can measure ahead of time.
Vibecoding amplifies all of it
None of this is new in principle. What's new is the volume and the trust.
Before, you'd go looking for a library because you'd heard of it. You saw its star count, its last commit date, its maintainer. A bit of social context entered the decision. Today an agent drops a dependency in the middle of a code stream you're skimming, and the confident tone does the rest. "Go ahead and install pdf-extract-pro" carries exactly the same calm assurance as a correct suggestion. The model doesn't know it's hallucinating, so it doesn't warn you.
And when you go full agent mode — the AI writes, installs, runs, and iterates on its own — the human verification window collapses to zero. The ghost package is downloaded and executed before your eyes ever land on it. The attack surface isn't your keyboard anymore. It's the autonomous loop.
What I actually do before every install
I don't have a magic fix to sell you. I have reflexes, and they fit in a few lines.
I never trust a package name an AI suggests. Not once. Before installing anything that came from an assistant, I open the package's page on the official registry. First published recently and suspiciously? Zero historical downloads? An anonymous maintainer with no other project? An empty or auto-generated description? All signals. A legitimate package has a history; a freshly registered ghost has none.
I check that the name matches the real project. requests-oauthlib, not requests-oauth. The source repo linked from the registry exists, it's active, and its name lines up. One minute of cross-checking.
I lock my dependencies. Lockfiles (package-lock.json, poetry.lock, uv.lock, a pinned requirements.txt with hashes). Once a clean dependency is in, it can't be silently swapped out. The lockfile is your long memory against drift.
I use an allowlist when the stakes deserve it. On serious projects, dependencies come through an internal mirror or a proxy registry that only serves what's been vetted. The agent can hallucinate whatever it likes: if it's not on the allowlist, it doesn't install.
I separate generation from execution. The AI proposes; it doesn't install on its own into an environment that has access to my secrets. A first cold pass — no network, no credentials — costs a few seconds and catches most of it.
The real shift to grasp
Vibecoding doesn't make your code less safe line by line. It moves the vulnerability upstream: into the now-delegated choice of what you install. The attacker no longer needs to fool you. They just need to know the reproducible blind spots of the model advising you — and to have planted a trap there before the question even came up.
The takeaway fits in one sentence, and you should make it a permanent reflex: a package name suggested by an AI isn't a source, it's a hypothesis to verify. Treat every generated dependency as unknown code from a stranger — because, quite literally, that's what it is. The day you blindly install what the machine imagines, you're not coding anymore: you're signing a blank check to whoever read its dreams before you did.