Every software supply chain attack of the last decade needed something to go wrong first. A maintainer account got compromised. A build server was misconfigured. A developer fat-fingered a package name. Slopsquatting needs none of that. It works when every system is behaving exactly as designed, because the vulnerability is not in your infrastructure. It is in the confident, fluent, entirely fictional package name your coding model just produced, and in the agent that installed it without ever asking whether the thing existed yesterday.
An Attack That Requires No Vulnerability
Start with the mechanic, because it is almost insultingly simple. Language models generate plausible text. When you ask one how to strip unused imports from a TypeScript project, it produces a code block, an install command, and a package name. Most of the time that name belongs to a real package. Sometimes it does not. The model has assembled a name that fits the shape of npm naming conventions, matches the semantics of your request, and reads exactly like a package that ought to exist. It just was never published by anyone.
Now add the attacker. They do not need to compromise anything. They query the popular models a few thousand times with realistic developer prompts, collect every package name that comes back, filter for the ones that resolve to 404 on the registry, and register them. The names are free. Publishing is free. Then they wait, because they know the models will keep producing those same names, and eventually a developer or an agent will run the install command without checking.
That number deserves a moment. Roughly one in five package recommendations from AI coding tools points at something that does not exist. The rate varies by model, by ecosystem, and by how obscure the task is, but the direction is consistent, and the important property is not the average. It is the repeatability. The same model, given similar prompts, tends to hallucinate the same names. That turns a random error into a targetable one. An attacker does not need to guess what a model might invent. They can measure it, and then they can own it.
"Threat actors register package names that do not exist but that AI coding tools reliably tend to hallucinate, then wait for a developer or an agent to run the install command without checking that the name is real."
Why Models Invent Package Names in the First Place
It helps to understand why this specific failure is so durable, because that determines whether you can expect it to go away. Package names sit in a semantic dead zone for language models. They look like language, they follow readable conventions, and they carry meaning that maps cleanly onto intent. A model that knows eslint-plugin-import exists and thatunused-imports is a concept in TypeScript tooling will happily produce unused-imports as a package name, because that is a sensible name for a package that does that job. The model is not reasoning about a registry. It is completing a pattern.
The failure mode is worse for anything the model has partial knowledge of. One documented case involved a package name that was produced by conflating two real tools, taking the prefix of one and the suffix of the other and generating a name that reads as legitimate to anyone who knows both tools. That is not a random string. It is a name a thoughtful maintainer might genuinely have chosen, which is exactly why it slides past review. The same property that makes model output useful, that it is idiomatic and plausible, is what makes this class of error invisible.
None of this is fixable by making models better at code. The registry is external state that changes daily, and no training cutoff can track it. A model can be excellent at TypeScript and still have no reliable way to know whether a name resolves. This is the same structural gap that makes "almost right" output the top developer frustration in Stack Overflow's survey of 49,000 developers, where 84% use AI tools and only 3% highly trust them. Almost right is the whole problem. A package name that is almost right is a name someone else owns.
Agents Changed the Economics
Package hallucination has been documented since 2023. It stayed a curiosity for two years for one reason: a human sat between the suggestion and the install. Developers do not blindly paste every command a chat window produces. They glance at the name, notice they have never heard of it, search for the docs, find nothing, and move on. The hit rate for an attacker was low enough that registering thousands of names was not worth the effort.
Autonomous coding agents removed that friction completely. An agent working through a task does not have a mental model of which packages are famous. It has a goal, a shell, and a tolerance for retrying. When the install fails, its instinct is not suspicion but iteration: try a different version, try a different name, try the scoped variant. Reporting from mid-2026 found that agents routinely skip package verification entirely, and attackers have been explicitly targeting that blind spot.
Exploits human error
reqeusts and waits for someone to mistype requests. Hit rate is bounded by how often humans slip. Defenses are name similarity scanners and registry-side blocking, both of which work reasonably well because the malicious name is a measurable edit distance from a real one.Exploits machine confidence
unused-imports, a name no human would flag as suspicious because it is a perfectly good name. Hit rate is bounded by how often models generate it, which is measurable, repeatable, and rising with agent adoption. Edit-distance scanners see nothing, because there is no real package to be near.That comparison is the reason existing controls miss this. Nearly every supply-chain defense built between 2018 and 2024 assumes the malicious package is impersonating a real one. Similarity detection, namespace reservation, and popular-package shadowing alerts all key on proximity to something legitimate. A hallucinated name has no legitimate twin. It occupies empty namespace. To a scanner it looks like an ordinary new package with a low download count, which describes several thousand honest packages published every week.
What the Live Incidents Actually Look Like
The theoretical phase ended some time in late 2025. The most widely cited case is an npm package published under a name that AI tools repeatedly suggested for a common TypeScript linting task. It was reported, and npm placed a security hold on it. That should have been the end of the story. It was not. As of early February 2026, the package was still recording roughly 233 downloads per week, months after it had been held.
Those 233 weekly downloads are the most instructive number in this whole story. They are not evidence of an active compromise. They are evidence of an ongoing, automated demand signal for a package that never should have existed, generated by models and pipelines that have no idea anything is wrong. Take down the package and the demand persists. Register the name again under a different account, or find the next hallucinated name in the same cluster, and the demand is already there waiting.
This is what makes slopsquatting structurally different from a normal malicious-package incident. In a conventional case, removal ends the exposure. Here, removal addresses the artifact and leaves the generator running. Security teams are used to treating a takedown as closure. In this class of attack the takedown is closer to mopping while the tap is open.
Why This Lands Hardest in CI, Not on Laptops
Most teams think about this as a developer workstation problem. It is worse than that. The workstation is where the name gets introduced; the pipeline is where it gets weaponised. A developer accepting an agent's suggestion commits apackage.json change. Review passes, because a new dependency called unused-imports in a PR titled "clean up lint config" is entirely unremarkable. The pipeline then installs it on a runner that holds deploy credentials, and the install script runs before a single test executes.
This is the same category of exposure we described in prompt injection remaining unsolved, where every published defense failed more than 90% of the time in a joint lab study, and the practical conclusion was to treat agent security as a supply-chain problem rather than a prompting problem. Slopsquatting is the literal version of that argument. The agent does not need to be jailbroken. It needs to be helpful at the wrong moment.
It compounds with the identity problem too. If your build agents hold long-lived credentials, and if you are anywhere near the organisations we covered in the non-human identity crisis where agents outnumber employees 80 to 1 and only 21% keep a real-time registry, then an install-time script is not a contained event. It is an entry point into a credential environment nobody has fully enumerated.
Five Controls That Actually Stop It
None of what follows is novel. That is deliberate. This threat is new, but it is defeated by supply-chain hygiene that has existed for years and that most teams have partially implemented and never finished. The work is in closing the gaps, not in buying anything.
1. Resolve existence before you resolve intent
Add a pre-install gate that checks every package name against the registry and against your existing lockfile, and that fails loudly on anything new. The check is a single API call per name and takes milliseconds. What matters is not the check itself but where you put it: it belongs in the agent's tool definition, not in a developer's habit. An agent that can only install from a verified set cannot install a name that has never existed, regardless of what the model believes.
2. Pin lockfiles and verify hashes, everywhere
Lockfile pinning with integrity hashes is the single highest-value control, and the reason is that it changes the failure mode from silent to loud. With npm ci against a committed lockfile, or pip with --require-hashes, an unrecognised package cannot enter the build at all; it has to enter through a reviewed lockfile change first. That moves the decision from a runner with credentials to a pull request with a human on it. Teams that allow npm install in CI have given that up without noticing.
3. Disable install scripts by default
Run installs with --ignore-scripts and maintain a short allowlist of packages that genuinely need lifecycle hooks. Most do not. This one control converts the majority of malicious packages from an immediate compromise into an inert directory of files that never executes. It is unglamorous, it occasionally breaks a native module, and it is worth the friction.
4. Take autonomous install away from the agent
An agent should be able to propose a dependency and be unable to add one. Route new dependencies through a human gate sized to the blast radius, exactly the reversibility principle behind the maker-checker pattern. Adding a direct dependency is irreversible in the sense that matters: once install-time code has run on a machine with secrets, you cannot un-run it. That earns a gate. Editing a function body does not.
5. Require provenance on every new direct dependency
For any package entering the tree for the first time, require three facts in the PR: the repository it builds from, its publication age, and its download history. A package that is three weeks old, has no linked source repository, and shows a flat download curve is not necessarily malicious, but it is necessarily unreviewed. Make that visible at review time and the hallucinated names stop clearing the bar, because they have no history to show.
What This Costs You
Being honest about friction is the only way these controls survive contact with a delivery deadline. Lockfile enforcement costs nothing after the first week of fixing pipelines that were quietly relying on floating versions. Disabling install scripts costs a handful of build failures on native modules, all resolvable through the allowlist. The provenance requirement adds perhaps three minutes to a review that introduces a new dependency, which for most teams is a few times per week.
Removing autonomous install is the one people push back on, because it visibly slows agents down, and the whole reason teams adopted agents was speed. The counterargument is proportionality. Agents generate a very large number of small edits and a very small number of dependency changes. Gating the rare, high-consequence action while leaving the common, low-consequence action ungated costs almost nothing in throughput. Teams that instead gate everything, or gate nothing, are the ones that end up either abandoning agents or explaining an incident.
How to Tell Whether You Are Already Exposed
Before you change anything, find out where you stand. Four questions get you an honest answer in an afternoon, and every one of them is answerable from data you already hold.
First, list every direct dependency added in the last six months and sort by publication age at the time it was added. Anything that was less than ninety days old when it entered your tree deserves a look. Most will be legitimate; the exercise is calibration, not accusation. Second, grep your CI configuration for install commands that are not lockfile-strict. Everynpm install, yarn add, or barepip install in a pipeline is a place where an unreviewed name can enter a credentialed environment.
Third, check what your coding agents are actually permitted to run. Not what the policy document says, what the tool definitions and shell allowlists say. Teams are regularly surprised here, because agent permissions tend to be set once during an enthusiastic pilot and never revisited. Fourth, look at whether your dependency review is a human reading a diff or a bot approving version bumps. If it is the second, the review step you are counting on does not exist.
The output of that afternoon is a short, specific list, and it will almost always contain at least one pipeline that installs unpinned dependencies on a runner with deploy credentials. That is the thing to fix first, ahead of any policy writing. It is one configuration change, and it removes the mechanism the attack depends on.
The Larger Pattern Worth Noticing
Slopsquatting is the first widespread attack class whose distribution mechanism is a model rather than a network. There is no malicious link, no phishing email, no compromised update server. The delivery channel is the assistant your team already trusts, and the payload is a name. That is a genuinely new shape, and it will not be the last one. Anywhere a model produces an identifier that maps to a namespace someone else can register, the same attack is available. Package names today. Container image tags, model repository names, MCP server identifiers, and skill or plugin names are all sitting in the same position.
The lesson generalises cleanly. Treat every identifier a model produces as untrusted input rather than as a result. Not because the model is adversarial, but because the namespace is public and the model has no way to check it. That single reframing catches slopsquatting and most of what follows it, and it costs one existence check in the right place.
The teams handling this well in 2026 are not the ones with the most security tooling. They are the ones that drew a clear line between what an agent may propose and what an agent may execute, and put every irreversible action on the far side of it. That line is cheap to draw now and expensive to draw after an incident report. The models will keep inventing names. The only variable you control is whether inventing one is enough to get code running on a machine that holds your credentials.
Tags
Share
Building something like this? See how we ship it or start a project.