Slopsquatting: The AI Supply Chain Attack Nobody Patched

Developer reviewing terminal output on a laptop while using an AI coding assistant to install packages

You paste an error into Claude or Cursor, it suggests pip install requests-oauth2client-helper, you install it, tests pass, you ship. Three weeks later your CI secrets are exfiltrating to an IP in a country you've never sold to. The package was hallucinated by an LLM last quarter. Someone else registered the name before you did.

That's slopsquatting. It's typosquatting's smarter cousin, and if you use AI coding tools — which at this point is most of us — you are the attack surface.

What slopsquatting actually is

Slopsquatting is a supply chain attack that weaponizes LLM hallucinations. When a coding assistant confidently invents a package name that doesn't exist (react-safe-dompurify, openai-tokenizer-fast, stripe-webhook-verifier-v2), an attacker registers that name on npm, PyPI, or crates.io and ships malicious code inside it. The next developer who gets the same hallucination — and they will, because LLMs are deterministic-ish under similar prompts — installs the attacker's package.

The name was coined by security researcher Seth Larson, and the mechanism was demonstrated in the 2025 arXiv paper "We Have a Package for You!" by Spracklen et al., which found that a meaningful fraction of package suggestions from popular code LLMs point to nonexistent packages, and that the same hallucinated names recur across independent prompts. That recurrence is the whole attack — repeatability turns a typo into a market.

The important distinction:

Attack Mechanism Who gets tricked
Typosquatting Registers reqeusts hoping you fat-finger requests Humans mistyping
Dependency confusion Registers your internal package name on a public registry Package managers preferring public sources
Slopsquatting Registers a name an LLM invented and repeats AI coding assistants and the humans trusting them

Typosquatting relies on your mistake. Slopsquatting relies on the model's mistake — and you copy-pasting it.

Why AI coding assistants make this worse

LLMs hallucinate package names for the same reason they hallucinate function signatures: they pattern-match on what a plausible name looks like, not on what exists. When Cursor tells you to import fastapi_ratelimit, it isn't checking PyPI. It's completing the pattern fastapi_<verb>.

Three things compound the risk for solo developers and small teams:

  1. You don't read every install line. When an agent runs pip install -r requirements.txt inside an autonomous loop, nobody is inspecting the diff line by line.
  2. Same prompt, same hallucination. Researchers found high recurrence rates for phantom package names across runs. That's a durable target for an attacker — register once, harvest for months.
  3. Auto-approve is the default in agent mode. Claude Code, Cursor Agent, and Windsurf Cascade will all execute shell commands with varying levels of confirmation. Turn confirmation off "for speed" and you've automated the attack path.

If you run a one-person SaaS shipping fast with Claude Code and yolo-mode installs, you are the ideal victim: production access, weak review, no security team.

A concrete attack walkthrough

Here's how the chain plays out in practice. Assume a solo founder building a Stripe webhook handler.

Step 1 — Developer prompts the assistant:

Add signature verification for Stripe webhooks. Use a small
well-maintained library, not the full stripe SDK.

Step 2 — LLM confidently suggests:

# assistant output
from stripe_webhook_verify import verify_signature

def handle(request):
    verify_signature(
        payload=request.body,
        signature=request.headers["Stripe-Signature"],
        secret=os.environ["STRIPE_WEBHOOK_SECRET"],
    )

Then:

pip install stripe-webhook-verify

The library sounds real. It fits the naming convention. It doesn't exist.

Step 3 — Attacker got there first. A researcher (or an adversary) scraped hallucinated names from public model outputs, registered stripe-webhook-verify on PyPI six months ago, and shipped a package with a working verify_signature function that also — on import — reads ~/.aws/credentials, .env, and ~/.config/gh/hosts.yml and posts them to a Cloudflare Worker.

Step 4 — Your CI runs it. Because you set pip install as a pre-test step in GitHub Actions, the exfiltration runs with whatever secrets your runner has — often more than the local dev has, because CI needs deploy keys.

Step 5 — You never notice. Tests pass. The malicious code only fires once on import. Your webhook works. The attacker owns your infrastructure by dinner.

Nothing in this chain requires the developer to be careless. It requires them to trust the model.

How to detect and prevent slopsquatting

Prevention here is not one control; it's a stack. Below is the layered approach that actually holds up in a small team.

1. Verify every package the model suggests

Before any install, check the package on the official registry. This is a one-liner you can bind to your editor or run as a pre-commit hook:

#!/usr/bin/env bash
# verify-pypi.sh — refuses to install packages that look sketchy
set -euo pipefail

PKG="$1"
INFO=$(curl -sf "https://pypi.org/pypi/${PKG}/json") || {
  echo "❌ ${PKG} not found on PyPI. Possible hallucination."
  exit 1
}

FIRST_UPLOAD=$(echo "$INFO" | jq -r '.urls[0].upload_time // "unknown"')
DOWNLOADS=$(curl -sf "https://pypistats.org/api/packages/${PKG}/recent" \
  | jq -r '.data.last_month // 0')

echo "✅ ${PKG} exists"
echo "   first upload: ${FIRST_UPLOAD}"
echo "   last-month downloads: ${DOWNLOADS}"

if [ "$DOWNLOADS" -lt 1000 ]; then
  echo "⚠️  Low downloads — treat as untrusted."
fi

The heuristics that matter: package age, download volume, GitHub repo linkage, and maintainer history. A "signature verification library" published two weeks ago with 40 downloads is not what a mature LLM should be citing.

2. Pin and hash everything

The Python ecosystem has pip install --require-hashes. Use it. In npm, use npm ci against a locked package-lock.json. This won't stop the first install of a malicious package, but it stops the silent swap variant where an attacker publishes a benign v1.0.0, waits for adoption, then poisons v1.0.1.

# requirements.txt
stripe==11.4.1 \
    --hash=sha256:abc123...
requests==2.32.3 \
    --hash=sha256:def456...

3. Isolate the agent's shell

Never let Claude Code or Cursor Agent run pip install, npm install, or cargo add against your host Python or global node. Every project gets a container or at minimum a venv, and the agent runs inside it. If a hallucinated package exfiltrates, it exfiltrates from a sandbox with no real credentials.

A minimal devcontainer.json for AI-assisted work:

{
  "image": "mcr.microsoft.com/devcontainers/python:3.12",
  "runArgs": ["--network=bridge", "--cap-drop=ALL"],
  "mounts": [
    "source=${localWorkspaceFolder},target=/workspace,type=bind"
  ],
  "remoteEnv": {
    "AWS_ACCESS_KEY_ID": "",
    "STRIPE_SECRET_KEY": ""
  },
  "postCreateCommand": "pip install --require-hashes -r requirements.txt"
}

Empty out prod-adjacent env vars. The agent gets a working shell with no keys worth stealing.

4. Use an allowlist proxy

For teams past two people, front your package installs with a proxy like Sonatype Nexus, JFrog Artifactory, or the free pypi-mirror pattern. Configure it to serve only packages your team has approved. A hallucinated name returns 404, the install fails loudly, and the developer has to justify adding it.

5. Static-scan the install script itself

Malicious packages usually run their payload in setup.py, postinstall, or on first import. Tools like pip-audit, npm audit, socket.dev, and guarddog scan for suspicious patterns — outbound network calls at install time, obfuscated strings, os.system calls, filesystem reads outside the package. Add one to CI. Fail the build on high-severity findings.

# .github/workflows/security.yml
name: supply-chain
on: [pull_request]
jobs:
  guarddog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: '3.12' }
      - run: pip install guarddog
      - run: guarddog pypi verify requirements.txt

6. Treat AI-suggested imports as untrusted input

The mental model shift: an LLM-suggested pip install line is user input. You wouldn't run arbitrary user input as shell. Stop running arbitrary model output as shell.

What to change in your Claude Code / Cursor workflow

Specific settings that reduce slopsquatting risk without killing productivity:

Claude Code:

  • Keep allowedTools explicit. Don't put Bash(pip install:*) on the always-allow list. Force a confirmation on install commands.
  • Use per-project CLAUDE.md to instruct: "Before suggesting a package, verify it exists on PyPI/npm and has >10k weekly downloads. If unsure, say so." This won't eliminate hallucinations but it cuts the confident-wrong ones.
  • Run Claude Code inside a devcontainer, not against your host user.

Cursor / Windsurf:

  • Turn OFF auto-run for shell commands in agent mode. Yes, it's slower. Slower is the point.
  • Use .cursorrules to require the model to cite the package's GitHub URL when it recommends one. Fabricated URLs are easier to spot than fabricated names.

Any AI tool:

  • Log every install command the agent proposes. Weekly, grep the log for packages you don't recognize. This takes ten minutes and has caught real issues in client environments.

Here's a simple guard I add to most projects — a pre-commit hook that blocks commits introducing new dependencies without a justification comment:

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: dep-justification
        name: require justification for new deps
        entry: bash -c '
          git diff --cached requirements.txt package.json 2>/dev/null \
          | grep -E "^\+[^+]" \
          | grep -v "^\+#" \
          && echo "New dep detected. Add a # justification: comment." \
          && exit 1 || exit 0
        '
        language: system

Small friction. Big signal.

Common mistakes I see in small teams

Working with solo founders and small ops teams shipping AI-assisted code, the same anti-patterns come up:

  • "The LLM is usually right, so I skip the check." Usually right is the entire attack surface. Slopsquatting exists precisely because "usually right" packages are the ones you install without reading.
  • Sharing one .env between dev and prod. When the agent's sandbox leaks, it leaks everything.
  • No lockfile in production deploys. pip install -r requirements.txt in a Dockerfile with no hashes means every rebuild is a fresh trust decision.
  • Trusting pip search-style suggestions from the model. Search-shaped output from an LLM is not a search. It's a completion.
  • Assuming npm/PyPI takedown is fast. Malicious packages routinely stay live for days before removal. Your build ran in minutes.

None of these mistakes are stupid. They're all what "moving fast" looks like when nobody warned you about this specific failure mode.

Where this is heading

Two things are true at the same time. First, registries are starting to react — PyPI has expanded malware scanning, npm has provenance attestations via Sigstore, and Socket-style scanners are getting embedded into more package managers. Second, agents are getting more autonomous. The window between "model hallucinates a name" and "agent installs it in prod" is shrinking, not growing.

The practical answer isn't to stop using AI coding tools. That ship sailed and you'd lose to teams that don't. The answer is to treat the agent like a fast, competent contractor who occasionally lies with total confidence — which is exactly what it is. You would not give that contractor root on your prod box. Don't give the agent root either.

How BizFlowAI approaches this

When we build Claude Code and MCP-based pipelines for clients, dependency handling is not an afterthought. Every project runs inside a locked devcontainer with no production credentials, allowedTools is explicit (never blanket Bash(*)), and package installs go through a verified-registry step before they hit the environment. We wire pip-audit or guarddog into CI so a slopsquatted package fails the build loudly instead of silently exfiltrating. For teams past two developers we set up an internal proxy so hallucinated names return 404 instead of arbitrary code execution.

The reason this matters for solo founders and small teams isn't paranoia — it's that these controls take a few hours to set up once and then run forever. If you're already shipping with Claude Code or Cursor and want a second set of eyes on your agent's blast radius, book a discovery call and we'll walk through the specific hardening for your stack.


Work with BizFlowAI

If you'd rather have this built for you, that's what we do: production AI automation for solo founders and small teams — agents, integrations, and document pipelines that actually ship.

Book a free discovery call — 30 minutes, we map the highest-ROI automation in your workflow. No pitch deck, just engineering.

More guides like this on the BizFlowAI blog.

Frequently asked questions

What is slopsquatting?

Slopsquatting is a software supply chain attack that exploits package names hallucinated by AI coding assistants like Claude Code, Cursor, or Copilot. Attackers scrape nonexistent package names that LLMs repeatedly invent, then register those names on registries like PyPI or npm with malicious code inside. When another developer receives the same hallucination and installs the package, the attacker's payload runs. The term was coined by security researcher Seth Larson.

How is slopsquatting different from typosquatting?

Typosquatting relies on humans mistyping a package name like 'reqeusts' instead of 'requests'. Slopsquatting relies on an LLM inventing a plausible-sounding package name that doesn't exist, then a developer trusting the AI and installing it. The attack surface is the model's mistake plus human trust, not human typos. Because LLMs tend to repeat the same hallucinations across similar prompts, attackers can register a name once and harvest victims for months.

How can I prevent slopsquatting in my AI coding workflow?

Verify every AI-suggested package on the official registry before installing, checking age, download count, and repo linkage. Pin dependencies with hashes using pip's --require-hashes or npm ci with a lockfile. Run AI agents inside a container or devcontainer with no production credentials in the environment. Add supply chain scanners like guarddog or pip-audit to CI, and disable auto-approve for install commands in Claude Code or Cursor.

Why do LLMs hallucinate package names that don't exist?

LLMs generate package names by pattern-matching on what plausible names look like, not by checking a registry. A model completing 'fastapi_' will predict a likely suffix like 'ratelimit' whether or not that package exists on PyPI. A 2025 arXiv study by Spracklen et al. found that a meaningful fraction of package suggestions from popular code LLMs point to nonexistent packages, and the same phantom names recur across independent runs.

Are auto-approve agent modes in Claude Code and Cursor safe for installs?

No. Auto-approve or yolo modes let the agent run pip install, npm install, or cargo add without human review, which automates the entire slopsquatting attack path. If the LLM hallucinates a package name that an attacker has already registered, the malicious code executes with your credentials. Keep install commands off the always-allow list and require explicit confirmation, or restrict the agent to a sandboxed container with no real secrets.