---
title: "Slopsquatting: How AI Hallucinated Packages Become a Supply Chain Attack"
description: "Slopsquatting is when an attacker registers the package name an AI coding tool keeps hallucinating, then waits for someone to install it. Here's how it works and how to defend against it."
image: "https://foundrysoft.co/api/og?type=article&title=Slopsquatting%3A+How+AI+Hallucinated+Packages+Become+a+Supply+Chain+Attack&cat=Tutorial+%2F%2F+Security&rt=12+min+read&au=Varun+Raj+Manoharan&dt=2026-08-01"
url: "https://foundrysoft.co/blog/slopsquatting-ai-hallucinated-packages-supply-chain"
---

Tutorial // Security 2026-08-01 12 min read

# Slopsquatting: How AI Hallucinated Packages Become a Supply Chain Attack

Slopsquatting is when an attacker registers the package name an AI coding tool keeps hallucinating, then waits for someone to install it. Here's how it works and how to defend against it.

![Varun Raj Manoharan](https://foundrysoft.co/images/about/founder.webp)

Varun Raj Manoharan Founder & Principal Engineer

Slopsquatting AI Security Supply Chain Attack Dependency Verification Coding Agents

## Key takeaways

-   Slopsquatting works because AI hallucinations of package names are repeatable, not random. In one study, 43% of hallucinated package names appeared on every one of ten identical reruns.
-   Researchers identified 127 package names that every major frontier model consistently hallucinates, 109 on PyPI and 18 on npm, which is a small enough list for an attacker to squat exhaustively.
-   A 2026 Sonatype analysis found roughly 27.8% of dependency recommendations from the leading model were hallucinations, including versions that do not exist.
-   Autonomous coding agents that run their own install commands remove the one step, a human reading the line before hitting enter, that used to catch a wrong package name.

Ask a model to write an import for a linting fix, and there's a real chance it hands you `unused-imports` instead of the actual package, `eslint-plugin-unused-imports`. If you or your agent runs `npm install unused-imports`, you get whatever code is sitting at that name on the registry. As of early February 2026, something was: a package still live and recording roughly 233 weekly downloads, despite npm having security-held it.

That's the entire attack. A model suggests a package that doesn't exist. Someone registers the name. The next developer, or the next agent, who gets the same suggestion installs whatever the attacker put there. No exploit, no phishing email, just a gap between what the model said and what actually exists on the registry, with someone sitting in that gap collecting installs.

The term for this is slopsquatting, a portmanteau of "AI slop" and "typosquatting" coined by Seth Larson, Developer in Residence at the Python Software Foundation. Typosquatting relies on a human mistyping a package name. Slopsquatting doesn't need a typo. It relies on a model being confidently, consistently wrong, and on someone trusting the suggestion enough to skip the check they'd normally do before installing something.

The reason models do this at all is not mysterious. A model trained on a huge amount of code has seen thousands of real package names that follow predictable patterns: `eslint-plugin-x`, `python-x`, `x-utils`. When it needs to fill in a package it hasn't actually memorized, it falls back on those patterns and produces something that looks exactly like a real package name should look. `unused-imports` fits the shape of a real npm package perfectly. It just isn't one. That's also why the same wrong name keeps showing up: the model isn't rolling dice each time, it's reproducing the most statistically plausible answer to a question with a specific, recurring shape.

## Why a single hallucination isn't the threat

A model inventing a package name on one lucky prompt is not, by itself, exploitable. Nobody can register a name in advance for words a model might string together once. The attack only works because hallucinated package names aren't scattered noise. They cluster.

Researchers testing this re-ran identical prompts ten times each and found that 43% of hallucinated package names showed up on every single rerun. That number is the whole mechanism. It means a meaningful share of hallucinations aren't a one-off fluke of sampling temperature, they're the model's default answer to that particular prompt, reproducible across sessions, across days, probably across users typing something close enough. An attacker doesn't need to guess. They can run the same prompts researchers run, see which names repeat, and register those.

The scale of the target list makes this worse than it sounds. Researchers identified 127 package names, 109 on PyPI and 18 on npm, that every major frontier model consistently hallucinates. A hundred and twenty-seven names is not a haystack. It's a list an attacker can work through by hand in an afternoon, checking each one against the registry and squatting whichever are still open. Contrast that with typosquatting, where the attacker has to guess which misspellings a human will actually type. Here the models have already done the enumeration and published the shortlist, in effect, just by being predictable.

A 2026 Sonatype analysis put a number on how often this class of error shows up in the first place: roughly 27.8% of dependency recommendations from the leading model were hallucinations, including versions that don't exist, not just package names. That's not a rare edge case in a niche language. It's a coin flip's neighbor, happening constantly, to every developer who asks a model what to install. The Cloud Security Alliance published a research note on slopsquatting in April 2026, which is a reasonable signal that this moved from curiosity to something security teams are tracking as a real category.

## Coding agents remove the one checkpoint that used to catch this

For years, the implicit safety net against a bad package name was a human reading the install command before running it. Even a distracted developer pasting a Stack Overflow snippet tends to glance at the name. It looks slightly off, they pause, they check.

An autonomous coding agent doesn't have that pause built in. If an agent decides it needs a dependency to satisfy a task, resolves the import, and runs the install itself, the sequence from hallucination to `pip install` or `npm install` can complete with nobody reading the line. The agent isn't being careless in any sense you could call negligent. It's doing exactly what it was built to do: closing the loop between "I need this" and "now I have it," fast, without a human in that loop to notice the name doesn't match anything the developer has heard of.

This is the part that makes slopsquatting specifically an agent problem rather than a generic AI problem. A chat interface that suggests code still routes through a person copying and pasting it. An agent with shell access and permission to install packages is the attack's ideal delivery mechanism: same hallucination rate, zero review step, and it can happen in a CI job or a background task where nobody's watching the terminal at all.

Real malicious packages exploiting this pattern have already accumulated tens of thousands of downloads. That's not from one person's agent going rogue. It's the aggregate of a lot of developers and a lot of agents hitting the same predictable hallucinations and installing what was waiting for them.

The environments where agents run make this harder to catch after the fact too. A developer's own laptop at least has a shell history and someone who might notice an unfamiliar process. A CI job or a scheduled background agent runs on a machine nobody is watching in real time, does its install, does its work, and exits. If the install pulled in something malicious, the first sign of trouble might be a security scan days later, or a credential that turns up somewhere it shouldn't, long after the moment where a person could have simply read the package name and said no.

## Defenses, roughly in order of how much they buy you

None of these close the gap by themselves. Together they cut the number of places a hallucinated package can slip through unnoticed.

### 1\. Lockfiles, and scrutiny when an agent touches one

A committed lockfile, `package-lock.json`, `poetry.lock`, `uv.lock`, `Pipfile.lock`, is the single most effective thing you already have. It pins exact versions and hashes, so a hallucinated package can't quietly ride in through a loose version range on a routine `npm install` once it's in the lockfile and locked.

The catch is that the lockfile only protects you until something adds an entry to it. If you let an agent edit dependencies, treat any commit that changes the lockfile as a distinct category from a commit that only changes application code. Diff it specifically:

Shell

Copy

```bash
git diff --stat -- package-lock.json poetry.lock
```

A one-line dependency bump touching hundreds of lockfile lines is normal. A new top-level entry you don't recognize, in a commit generated by an agent, is exactly the pattern this attack produces. Look at it before you look at anything else in that commit.

### 2\. Block installs below an age or download threshold

Most registries expose publish date and download counts, and several supply chain scanners (Socket, Snyk, and the OSS-heavy CI scanners) let you gate on both. A package published four days ago with a handful of downloads is not automatically malicious, everything starts there, but it is exactly the profile of a name someone just squatted after watching which hallucinations repeat. Pair a minimum-age check with a minimum-downloads check in CI and a brand-new dependency has to clear both before the build passes:

Shell

Copy

```bash
# npm: package-level metadata includes publish time
npm view <package> time.created

# pip: check PyPI's JSON API for the same
curl -s https://pypi.org/pypi/<package>/json | jq '.releases | keys[0]'
```

This doesn't stop a patient attacker who lets a squatted package age for a few months before weaponizing it, which does happen. It does stop the fast, high-volume version of the attack, where the payoff depends on catching developers within days of registering the name.

### 3\. `--ignore-scripts`, and its real limits

Shell

Copy

```bash
npm install --ignore-scripts
pip install --no-deps --require-hashes -r requirements.txt
```

`npm install --ignore-scripts` skips `preinstall`, `install`, and `postinstall` lifecycle scripts, which is where a lot of npm supply chain payloads actually execute: a script that runs on install, phones home, or drops a second-stage payload before you've even opened the package. pip doesn't run arbitrary install-time scripts the same way by default for wheels, but `--no-deps` combined with `--require-hashes` stops a malicious package from pulling in its own dependency tree unchecked and forces every package to match a hash you've already vetted.

What this doesn't do: stop malicious code that runs at import time or at runtime, once your application actually calls into the package. A package with no install script can still do damage the first time you `import` it. Treat `--ignore-scripts` as removing one execution point, not as a general-purpose defense.

### 4\. Private registry proxy with an allowlist

The strongest structural fix is routing installs through a private proxy (Artifactory, Verdaccio, a private npm/PyPI mirror) that only serves packages you've explicitly approved, rather than letting every developer and every agent resolve names against the public registry directly. A hallucinated package that was never on your allowlist simply isn't resolvable, no matter how convincingly a model suggests it.

The honest cost here is maintenance. Someone has to review and approve new packages, which is friction on every legitimate new dependency too, and an allowlist that's rubber-stamped without real review buys you nothing. This is worth it for teams running agents with install permissions in CI or in shared environments, where the blast radius of one bad install is higher than a single developer's laptop.

### 5\. CI checks on same-commit dependency additions

A pattern worth encoding directly into CI: fail the build, or at minimum flag it for review, when a commit adds a new dependency in the same diff as a large amount of agent-generated code. That correlation, new package plus a big chunk of code the agent just wrote to use it, is a decent proxy for "nobody had a reason to already know this package existed."

YAML

Copy

```yaml
# rough shape, not a drop-in action
- name: flag new dependencies
  run: |
    git diff --name-only origin/main... | grep -E 'package.json|requirements.txt|pyproject.toml' \
      && echo "::warning::Manifest changed in this PR, review new deps before merge"
```

This isn't a precise signal. Plenty of legitimate commits add a dependency and code that uses it in the same PR. Use it to route the diff to a human for a specific, fast check, not to block merges automatically.

### 6\. Review the manifest diff on its own, separately from the code

Reviewing `package.json` or `requirements.txt` as its own diff, not buried inside a five-hundred-line PR, is cheap and catches things a full-code review misses. A reviewer skimming logic changes is looking for bugs. A reviewer looking only at the manifest is looking for one thing: does every name in this list belong here. That's a much narrower question, and narrower questions get answered correctly more often.

## A ten-second check before installing anything a model suggested

Before running an install command a model handed you, whether you typed it or an agent is about to run it, look at four things on the registry page:

1.  **The repository link.** A real, actively maintained package links to a real GitHub repo with history that predates the package. A squatted name often links nowhere, or to an empty repo created the same week.
2.  **The publish date.** Anything published in the last few weeks deserves a second look, especially if it's a near-exact name for something well-known.
3.  **The download history.** A real, established package has a download curve with months or years of history. A squatted package has a flat line that starts recently, sometimes with a small spike if someone's already farming it.
4.  **The name itself, against the real one.** Is this `eslint-plugin-unused-imports`, or is it `unused-imports`, missing the plugin prefix a real ESLint plugin would carry? Slopsquatted names are usually a plausible-sounding shortening or reordering of the real thing, which is exactly why models hallucinate them in the first place, and exactly why they're easy to miss at a glance.

None of these take more than a few seconds once you know to look. The problem was never that verification is hard. It's that autonomous installs and habitual trust in model output both skip the step entirely.

## What none of this catches

Be clear-eyed about the limits. Every defense above targets a package that shouldn't exist getting installed. None of it touches a legitimate, already-trusted package that gets compromised after the fact, through a stolen maintainer token or a malicious update slipped into a real project's release. That's a different attack with a different defense (2FA on publishing accounts, reviewing changelogs on version bumps, pinning to specific commit hashes for anything security-sensitive), and no allowlist or lockfile check above substitutes for it.

The allowlist approach carries a real ongoing cost too. Every legitimate new package a team wants to adopt has to clear review before it's usable, and a team that treats that review as a checkbox rather than an actual look at the package defeats the point while still paying the friction. Age and download thresholds have their own failure mode: they penalize genuinely new, genuinely useful packages right alongside squatted ones, and a determined attacker can simply wait out whatever threshold you set before activating the payload.

None of this is a reason to skip the defenses. It's a reason to treat them as raising the cost of the attack rather than eliminating it, which is the honest description of most supply chain controls, not just these ones.

The fix that scales is not a tool. It's making the manifest diff a first-class thing someone looks at, every time, whether the change came from a person or an agent typing at machine speed. An agent that can write code and an agent that can also silently add a dependency to run it are two different levels of trust, and most teams are currently granting the second without having decided to.

#### Related reading

[Implementing Human-in-the-Loop AI Agents using Eve.dev and TypeScript

Ensure safety and accuracy in your AI workflows. Learn how to build human-in-the-loop authorization gates using Eve.dev's durable execution framework.

Eve.dev Human-in-the-Loop TypeScript

](https://foundrysoft.co/blog/eve-dev-human-in-the-loop)[Creating an Autonomous Coding Agent using Vercel AI SDK and MCP

Learn how to build your own AI software engineer. We use the new Model Context Protocol (MCP) to give the Vercel AI SDK agent access to read your local file system, write code, and execute bash commands safely.

Vercel AI SDK MCP Coding Agents

](https://foundrysoft.co/blog/vercel-ai-sdk-mcp-coding-agent)

#### Next Article

[

AI Agent Security After the First Sandbox Escape

](https://foundrysoft.co/blog/ai-agent-sandbox-escape-credential-hygiene)

Available for new projects

## Let's build something great.

Have a project in mind? We are an elite software and AI development studio ready to bring your ideas to production. Let's talk about your roadmap.

Start a Project [See our work](https://foundrysoft.co/work)

```json
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "FoundrySoft",
  "url": "https://foundrysoft.co",
  "logo": "https://foundrysoft.co/logo.svg",
  "description": "FoundrySoft builds production-grade software and AI systems for US companies, from an India-based team of senior engineers.",
  "sameAs": [
    "https://github.com/foundrysofthq",
    "https://www.linkedin.com/company/foundrysoft",
    "https://www.instagram.com/foundrysoft/"
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "FoundrySoft",
  "url": "https://foundrysoft.co"
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "Slopsquatting: How AI Hallucinated Packages Become a Supply Chain Attack",
  "description": "Slopsquatting is when an attacker registers the package name an AI coding tool keeps hallucinating, then waits for someone to install it. Here's how it works and how to defend against it.",
  "url": "https://foundrysoft.co/blog/slopsquatting-ai-hallucinated-packages-supply-chain",
  "mainEntityOfPage": "https://foundrysoft.co/blog/slopsquatting-ai-hallucinated-packages-supply-chain",
  "image": [
    "https://foundrysoft.co/images/blog/slopsquatting-ai-hallucinated-packages-supply-chain.webp"
  ],
  "datePublished": "2026-08-01",
  "dateModified": "2026-08-01",
  "keywords": "Slopsquatting, AI Security, Supply Chain Attack, Dependency Verification, Coding Agents",
  "author": {
    "@type": "Person",
    "name": "Varun Raj Manoharan"
  },
  "publisher": {
    "@type": "Organization",
    "name": "FoundrySoft",
    "logo": {
      "@type": "ImageObject",
      "url": "https://foundrysoft.co/logo.svg"
    }
  }
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://foundrysoft.co/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Blog",
      "item": "https://foundrysoft.co/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Slopsquatting: How AI Hallucinated Packages Become a Supply Chain Attack",
      "item": "https://foundrysoft.co/blog/slopsquatting-ai-hallucinated-packages-supply-chain"
    }
  ]
}
```
