# Slopsquatting

> Slopsquatting is registering a package name that AI coding tools hallucinate, so developers or agents who follow the AI's advice install attacker code.

Also known as: AI package hallucination, package hallucination attack, hallucinated package, hallucinated dependency

Source: https://socket.dev/glossary/slopsquatting

Last updated: 2026-10-27

Slopsquatting is a software supply chain attack in which someone registers a package name that AI coding tools invent, then waits for a developer or agent to install it. The underlying model error is called package hallucination. Models repeat the same fake names across prompts and vendors, so one registration can reach many victims.

The mechanism is a namespace gap. Code refers to packages by import names, CLI commands, and plugin shorthands, but a registry resolves a separate, flat namespace of distribution names that anyone can claim first. A model trained on code learns the first namespace well and guesses at the second. The most important fact is that the guesses are stable. In the [USENIX Security 2025 study of 16 code models](https://socket.dev/blog/slopsquatting-how-ai-hallucinations-are-fueling-a-new-class-of-supply-chain-attacks), 43% of hallucinated package names came back in all ten repeated runs of the same prompt. In 2026, [five frontier models from four vendors](https://socket.dev/blog/slopsquatting-targets-across-frontier-llms) produced the same 127 fake names.

Our position: slopsquatting is not mainly a model-accuracy problem, and typosquatting defenses will not catch it. Nearly half of hallucinated names are six or more edits away from any real package, so name-similarity checks have nothing to match. The control has to sit at the moment a developer or agent installs or runs a name for the first time. It has to check what the package contains and who published it, not merely whether the name exists.

## What is slopsquatting?

Slopsquatting is the registration of a package name that a large language model (LLM) hallucinated, so that code written or run on the model's advice installs the registrant's code. The word joins "AI slop" and [typosquatting](https://socket.dev/glossary/typosquatting). Python Software Foundation Developer-in-Residence Seth Larson coined it, and Andrew Nesbitt popularized it in April 2025.

Slopsquatting and typosquatting share a payoff and differ in who makes the mistake. Typosquatting bets that a human will mistype `requests` as `reqeusts`. Slopsquatting bets that a model will confidently write a name nobody ever published, and that the human or agent acting on it will not check. A typosquat needs a popular target to imitate. A slopsquat needs only a name the model keeps producing.

A slopsquatted package delivers its payload the way any [malicious package](https://socket.dev/glossary/malicious-package) does: install hooks, import-time code, or a command-line entry point. The targeting is what is new. The attacker does not guess what humans will mistype. The attacker queries models, collects the names they invent, and registers the ones that recur. Slopsquatting is the clearest supply chain risk specific to [AI-generated code](https://socket.dev/glossary/ai-generated-code-security), because the vulnerable artifact is a single line the model wrote: the install command.

## Two namespaces, one gap

Every package ecosystem has two names for the same thing. Source code uses the import name or the command name. The registry uses the distribution name. They often differ, and nothing in the language requires them to match.

Python shows the gap most clearly. `import sklearn` comes from the `scikit-learn` distribution, `import bs4` from `beautifulsoup4`, and `import attr` from `attrs`. The `huggingface-cli` command ships inside `huggingface_hub`. A model that has read millions of import lines learns the left side of each mapping far better than the right.

We queried PyPI's JSON API (`https://pypi.org/pypi/<name>/json`) and the npm registry on October 27, 2026 to see what each code-side name resolves to when someone types it into an installer.

| Name in code | Real distribution | What the code-side name resolves to (October 2026) |
| --- | --- | --- |
| import sklearn | scikit-learn | sklearn on PyPI: a deprecated placeholder from the scikit-learn project, uploaded December 2023, that fails to install and tells you to use scikit-learn |
| import bs4 | beautifulsoup4 | bs4 on PyPI: a dummy package from Beautiful Soup's maintainer that depends on beautifulsoup4 |
| import attr | attrs | attr on PyPI: an unrelated decorator library, last released in 2022 |
| huggingface-cli download … | huggingface\_hub | huggingface-cli on PyPI: 404 today, but registered as an empty research package in 2024 (see below) |
| import "@ember/service" | ember-source | @ember/service on npm: 404, and the @ember scope is owned, so no one else can publish it |
| ESLint plugins: \["unused-imports"\] | eslint-plugin-unused-imports | unused-imports on npm: a security-holding package since October 27, 2025, after npm removed versions that contained malicious code |

Three outcomes show up in that table. A maintainer can defend the code-side name, as Beautiful Soup and scikit-learn did. The `bs4` description states the intent plainly: "This is a dummy package designed to prevent namesquatting on PyPI." A stranger can already own the name, as with `attr`, which is harmless here but proves the name was open to anyone. Or the name can sit unclaimed, and then whoever registers it next decides what the install command does.

npm scopes close the gap structurally. The [npm documentation](https://docs.npmjs.com/cli/v9/using-npm/scope/) states that "only you can add packages in your scope," so `@ember/service` returns a 404 that no attacker can fill. Unscoped npm names, and every PyPI name, are first come, first served.

## How often do AI models hallucinate package names?

AI models hallucinated package names in 4.6% to 6.1% of code answers in 2026 tests, down from about 20% across older models. The [USENIX Security 2025 study](https://socket.dev/blog/slopsquatting-how-ai-hallucinations-are-fueling-a-new-class-of-supply-chain-attacks) by Spracklen et al. generated 576,000 Python and JavaScript samples from 16 models. It found that 19.7% of recommended packages did not exist. Commercial models averaged 5.2% and open source models 21.7%, and the samples contained 205,474 unique fake names.

Repetition is what makes those rates exploitable. The researchers re-ran 500 hallucination-triggering prompts ten times each. 43% of the fake names reappeared every time, and 58% appeared more than once. An attacker does not need anyone's prompt logs. A few hundred queries reveal which names a model will keep producing.

The 2026 frontier models narrowed the spread without closing the gap. [Aleksandr Churilov's replication](https://socket.dev/blog/slopsquatting-targets-across-frontier-llms), run from April 22 to 28, 2026, measured five models on the same prompt corpus across 199,845 responses.

| Model | Overall | Python | JavaScript |
| --- | --- | --- | --- |
| Claude Haiku 4.5 | 4.62% | 5.49% | 2.76% |
| Claude Sonnet 4.6 | 5.41% | 6.63% | 2.62% |
| Gemini 2.5 Pro | 5.80% | 6.75% | 3.61% |
| DeepSeek V3.2 | 5.89% | 6.69% | 3.78% |
| GPT-5.4-mini | 6.10% | 7.27% | 3.14% |

GPT-5.4-mini was tested at minimal reasoning effort and refused 32.14% of prompts, so its rate covers only the answers it gave. Python rates exceeded JavaScript rates for every model. Churilov suggests that newer models absorbed npm's naming conventions better than Python's mix of import names and distribution names, which is the namespace gap again.

Cross-model overlap matters more to an attacker than any single rate. All five models produced the same 127 fake names, so one registration reaches users of every vendor at once. [Churilov's paper](https://arxiv.org/pdf/2605.17062) puts it directly: "Single-model rate measurements understate the attack surface."

> Funnel from 127 package names hallucinated by all five frontier models to 53 registrable names

Socket and PyPI Security reviewed the 127 shared names through coordinated disclosure. PyPI's prohibited-name and normalization rules already blocked 68 of the 109 Python names, which left 41. Our review of the 18 npm names removed six false positives. Four were Ember.js virtual modules (`@ember/service`, `@ember/object`, `@ember/routing`, `@ember/controller`) that resolve through `ember-source`. One, `ssh-keys`, was an existing package. One, `metro-evaluator`, was already a security hold. That left 53 registrable names as of April 2026: 41 on PyPI and 12 on npm. The Ember cases are correct code with no matching registry entry, which is why a registry lookup alone overcounts hallucinations.

The paper's public examples included the npm name `css-color-stop`. On July 28, 2026, six days after our coverage of the study, someone registered it:

```bash
$ curl -s https://registry.npmjs.org/css-color-stop \
    | jq '{time, fileCount: .versions["0.0.0"].dist.fileCount, unpackedSize: .versions["0.0.0"].dist.unpackedSize}'
{
  "time": {
    "created": "2026-07-28T19:22:40.055Z",
    "0.0.0": "2026-07-28T19:22:40.251Z",
    "modified": "2026-07-28T19:22:40.538Z"
  },
  "fileCount": 1,
  "unpackedSize": 53
}
```

The tarball holds a 53-byte `package.json` with a name, a version, and nothing else, so today the package is harmless. It still shows the race. A published hallucination list is a registration list, and whoever reads it first decides what the name installs.

## Why typosquatting defenses miss slopsquatting

Typosquatting defenses compare a new name against popular names, and most hallucinated names are not close to anything. In the USENIX study, only 13.4% of hallucinated names were within an edit distance of 2 of a real package. Another 37.9% were 3 to 5 edits away, and 48.6% were 6 or more.

npm's registry-side rule shows the limit. Since December 2017, npm has [refused a new name](https://blog.npmjs.org/post/168978377570/new-package-moniker-rules) that matches an existing package once punctuation is removed. That rule blocks `reactnative` because `react-native` exists. A blended name like `react-codeshift` matches nothing after stripping punctuation, so the rule never fires.

Socket's [Possible typosquat attack](https://socket.dev/alerts/didYouMean) alert has the same blind spot by design. It ranks candidate names by similarity to much more popular packages, which catches `reqeusts` and has no reason to flag a plausible name that resembles no single target. Similarity checks still catch the 13.4% of hallucinations that are near-misses. They cannot be the primary control.

The punctuation rule has a second effect: a registry 404 does not prove a name is free. A target list built from 404s overcounts on npm, for researchers and attackers alike.

## How does a hallucinated package name reach an install?

A hallucinated package name reaches an install through three paths: a person copying a chat answer, a written artifact that preserves the name, and an agent that runs it directly. The second and third paths are where slopsquatting scales.

### A README: huggingface-cli

In 2024, security researcher Bar Lanyado [found](https://lasso.security/blog/ai-package-hallucinations) that several models kept telling users to run `pip install huggingface-cli`. The real command ships with `huggingface_hub`. Lanyado uploaded an empty package under the hallucinated name, and it received more than 30,000 authentic downloads in three months. The name had already escaped the chat window. [Alibaba's GraphTranslator README](https://github.com/alibaba/GraphTranslator/commit/4394d7227ae03b332c2f47a1971050b403c134e2) told readers to install it:

```bash
pip install -U huggingface_hub
pip install huggingface-cli
```

The first line installs the real package. The second line installs whatever owns the hallucinated name. On PyPI, installing a source distribution runs the package's build backend, so the owner's code executes during `pip install` itself. pip's [`--only-binary :all:`](https://pip.pypa.io/en/stable/cli/pip_install/) option refuses source distributions, at the cost of failing for any package that ships no wheel.

### A skill file: react-codeshift

On October 17, 2025, a single [commit](https://github.com/wshobson/agents/commit/65e5cb0) to the public `wshobson/agents` repository added 47 [agent skills](https://socket.dev/glossary/agent-skills) across 14 plugins. The `react-modernization` skill told agents to run a package that did not exist:

```bash
# Install jscodeshift
npm install -g jscodeshift

# React 16.9 codemod (rename unsafe lifecycle methods)
npx react-codeshift <transform> <path>
```

The name blends `jscodeshift`, the codemod runner, with `react-codemod`, the React transform collection. Forks copied the file unchanged, so one model error became a standing instruction in many repositories. A security researcher registered `react-codeshift` on January 14, 2026, as a placeholder whose description reads "Placeholder to prevent dependency confusion." The upstream skill has since been fixed.

### The agent loop: npx with no TTY

Agent execution removes the last human gate. When a requested package is missing locally, npm exec prints a confirmation prompt. The [npm exec documentation](https://docs.npmjs.com/cli/v12/commands/npm-exec) adds: "When standard input is not a TTY or a CI environment is detected, `--yes` is assumed." Most coding agents run commands in subprocess shells without a TTY. An [npx](https://socket.dev/glossary/npx-npm-package-runner) command in a skill therefore fetches and runs whatever owns the name, without asking.

> How a hallucinated npx command in an agent skill reaches code execution, with the name unclaimed and claimed

The figure traces the `react-codeshift` skill through six steps, in two states. Steps 1 to 4 are identical in both. (1) A model writes `npx react-codeshift …` into `SKILL.md`, with no check that the package exists. (2) The commit lands in a public repository, and forks copy the file. (3) An agent activates the skill and runs the command in a shell whose standard input is not a TTY. (4) npm exec finds the package missing locally and assumes `--yes`. In the unclaimed state, before January 14, 2026, (5) the registry returns 404 and (6) nothing runs, though every fork keeps shipping the broken command. In the claimed state, (5) the registry returns 200 with a tarball owned by whoever registered the name first, and (6) npm unpacks it into the npm cache, puts its `bin` on `PATH`, and runs it with the agent's credentials.

Install-script defaults do not help on this path. [npm v12 turned dependency install scripts off by default](https://socket.dev/blog/npm-12) in July 2026, and [pnpm 10 blocked lifecycle scripts by default](https://socket.dev/blog/pnpm-10-0-0-blocks-lifecycle-scripts-by-default) in January 2025. Both changes close the [install script](https://socket.dev/glossary/postinstall-scripts) path that most recent npm worms used. With `npx`, the package's own entry point is the thing the user asked to run, so there is nothing for a script policy to block. `uvx`, `pipx run`, and `bunx` work the same way.

## A timeline of slopsquatting evidence

The record so far is short, and most of it comes from registries and Git history rather than incident reports.

| Date | Event | Evidence |
| --- | --- | --- |
| March 28, 2024 | A researcher reports that an empty huggingface-cli package he uploaded to PyPI drew more than 30,000 downloads in three months. An Alibaba README tells users to install it. | Lasso Security write-up; GitHub commit 4394d72 |
| April 2025 | Seth Larson coins "slopsquatting." Andrew Nesbitt popularizes it. | Socket coverage |
| 2025 | USENIX Security study: 19.7% of 2.23 million recommended packages do not exist. | Spracklen et al. |
| October 17, 2025 | A commit adding 47 agent skills includes npx react-codeshift. | GitHub commit 65e5cb0 |
| October 27, 2025 | npm replaces unused-imports, the ESLint shorthand for eslint-plugin-unused-imports, with a security-holding package. The removed versions were published March 17 and September 15, 2025. | npm registry metadata |
| January 14, 2026 | react-codeshift is registered as an empty placeholder. | npm registry metadata |
| March 28 to April 9, 2026 | huggingface-cli appears on npm as two dev versions and is replaced by a security-holding package 12 days later. | npm registry metadata |
| April 22 to 28, 2026 | Five frontier models share 127 hallucinated names. 53 are registrable. | Churilov; Socket and PyPI review |
| July 28, 2026 | css-color-stop, one of the published names, is registered as a 53-byte placeholder. | npm registry metadata |

As of October 2026, we know of no publicly confirmed malware campaign that was shown to be built by harvesting model hallucinations. The registrations on record are research packages, defensive placeholders, and removed packages whose names sit in the namespace gap but whose origin is unproven. [`unused-imports`](https://socket.dev/npm/package/unused-imports) is the closest case. The name is the one an ESLint config uses, not the name of the package that provides the plugin, and npm removed it for malicious code. Nobody has shown that a model put it in front of its victims. We expect that evidence gap to close, because the economics favor the attacker: one registration, no popular target to imitate, and agents that execute without asking.

## How do you prevent slopsquatting?

You prevent slopsquatting by vetting every new package name at the moment it first enters a project or a shell, and by checking its publisher, age, and contents rather than only its existence. An existence check is the most common advice and the weakest control. Once an attacker registers the name, the check passes.

| Control | What it stops | What it misses |
| --- | --- | --- |
| Check that the name exists | Unclaimed hallucinations, which fail anyway | Every registered slopsquat. Existence is the attacker's goal. |
| Typosquat detection by name similarity | Near-miss names, about 13% of hallucinations | Fabricated and blended names with no close target |
| Install scripts off by default (npm v12, pnpm 10+) | Payloads in preinstall and postinstall | npx and uvx entry points, import-time code, Python source builds |
| Dependency cooldown (pnpm 11 defaults to 24 hours) | Names registered in reaction to a disclosure, inside the window | Names registered before anyone needs them. css-color-stop cleared a 24-hour window on July 29, 2026. |
| Lockfiles and pinning | Drift after a dependency was reviewed | The first introduction of a name. npx never touches the lockfile. |
| Scopes and defensive registration | Names maintainers anticipate, such as bs4, sklearn, @ember/\* | Names nobody anticipated. PyPI has no scopes. |
| Registry reservation lists | 68 of 109 shared PyPI names in 2026 | Names outside the list. npm has no shared hallucination blocklist. |
| npx --no or NPM\_CONFIG\_YES=false in agent environments | Any npx fetch of a package that is not already installed | Direct npm install and pip install commands |
| Package firewall | Known malware at install time, at any depth | Brand-new or empty packages with no verdict yet |

Our verdict: no single row is sufficient, and the right mix depends on who runs the command. For people, a [dependency cooldown](https://socket.dev/glossary/dependency-cooldown) plus a [package firewall](https://socket.dev/glossary/package-firewall) covers the most ground. pnpm 11 [ships a 24-hour minimum release age by default](https://socket.dev/blog/pnpm-11-adds-new-supply-chain-protection-defaults), and npm [added `minimumReleaseAge`](https://socket.dev/blog/npm-introduces-minimumreleaseage-and-bulk-oidc-configuration) in early 2026. For agents, add a hard rule. An agent may not install or `npx` a package that is not already in the lockfile until a check returns the publisher, the age, and what the code does. In our [analysis of the axios compromise](https://socket.dev/blog/hidden-blast-radius-of-the-axios-compromise), we recommend `npx --no --offline` in CI and `NPM_CONFIG_YES=false` for agent tooling, so `npx` errors instead of fetching. Treat an AI-suggested dependency like a pull request from a stranger.

Socket covers part of this, with a trade-off we chose on purpose. [Socket Firewall Free](https://docs.socket.dev/docs/socket-firewall-free) wraps npm, yarn, pnpm, pip, uv, and cargo (`sfw npm install <pkg>`) and blocks confirmed malware anywhere in the dependency tree. It only warns on AI-detected potential malware, so an unconfirmed verdict never breaks a build. The cost is that a freshly registered slopsquat with no confirmed verdict gets through. Earlier in the loop, [Socket MCP](https://socket.dev/blog/socket-mcp) gives an AI assistant a `depscore` tool, so the assistant can look up a package's supply chain, quality, and maintenance scores before it suggests the name.

## The fix belongs before the name is emitted

The cheapest place to stop slopsquatting is the model and the agent harness, not the registry. A coding agent that resolves every package name against the registry before it writes an install command would turn a silent hallucination into a visible error. Churilov's paper notes that agents with retrieval could in principle avoid these errors, but it did not test them. A registry lookup alone is not enough, as the Ember false positives show, so the check has to understand each ecosystem's module system. The harness also has to treat a brand-new package that matches a hallucinated name as suspect, not as confirmation.

Registries can help too. PyPI's existing prohibited-name and normalization rules blocked 68 of the 109 shared names in 2026. A coordinated list of cross-model hallucinations, reserved the way npm reserves names with security holds, would turn each published study from a target list into a blocklist. Until that list exists, every disclosure starts a race, and `css-color-stop` shows how short the race is.

Slopsquatting does not need models to be wrong often. It needs them to be wrong the same way, and they are.
