Slopsquatting — LLM-hallucinated package squatting

Slopsquatting — LLM-hallucinated package squatting

TL;DR: LLM code assistants reliably hallucinate package names that do not exist. Register those names on PyPI / npm first and you get RCE on every developer who copy-pastes the suggestion — typosquatting where the typo is generated by the model.

What it is

Term coined by Seth Larson / Bar Lanyado in 2024 for a typosquatting variant against AI-generated code. LLMs trained on millions of repos confabulate plausible-looking but non-existent package names — requests-helper, pandas-utils, langchain-tools-pro. Studies (Lanyado 2024, “Can you trust ChatGPT’s package recommendations?”) found 4-20% of suggested packages do not exist; many hallucinations are consistent — the same model emits the same fake name across many sessions and users. The attacker enumerates hallucinations, registers them on the public registry, and waits. When a developer pastes the snippet and runs pip install, the attacker’s code runs.

Preconditions / where it applies

  • Developer using an LLM coding assistant (Copilot, Cursor, Claude Code, ChatGPT) and pasting suggestions without manual verification of dependency lists.
  • Public package registry (PyPI, npm, RubyGems, crates.io, Maven Central) that allows new-name registration without prior-art checks.
  • Pairs cleanly with dependency confusion: register the hallucinated name on the public registry, watch corporate dev environments pull it in preference to internal mirrors.

Technique

  1. Harvest hallucinations. Query a model with a large bank of “how do I X in Python/Node” prompts. Parse the import/require/from lines. Diff against the live registry index. Keep names that (a) do not exist, (b) recur across queries (high persistence).
  2. Register. Create accounts on PyPI/npm; publish setup.py / package.json claiming the name. Most registries enforce no prior verification.
  3. Payload. Install hooks run on pip install (setup.py install_requires, entry_points) and npm install (preinstall, postinstall scripts) — execute immediately as the dev user. Steal ~/.aws/credentials, ~/.npmrc, ~/.git-credentials, SSH keys, environment variables; phone home; optionally drop a real implementation so the build succeeds and the dev does not notice.

    1
    2
    3
    4
    5
    
    // package.json
    {
      "name": "langchain-tools-pro",
      "scripts": { "postinstall": "node ./bootstrap.js" }
    }
    
  4. Dependency confusion chaser. If the hallucinated name collides with a private package some org actually has, the public version wins by default version-resolution rules in npm and many pip configs — see also supply-chain-attacks-on-models.

  5. Persistence. Keep the package fully functional so it stays installed; ship malicious code via a delayed update.

Detection and defence

  • Lockfiles + hash pinning: requirements.txt with --hash, package-lock.json, pnpm-lock.yaml, cargo.lock. Refuse new transitive deps without a review.
  • Resolve internal packages from a private index first; configure pip --index-url / npm .npmrc registry to a curated mirror that does not proxy unknown names.
  • Pre-install scanners: pip-audit, npm audit, socket.dev, snyk. Block install of packages younger than N days or with maintainer reputation below a threshold.
  • Sandbox pip install / npm install in CI (no network egress to attacker domains, no access to host creds).
  • Code-review LLM suggestions for new imports specifically; treat new top-level deps as a code-review checkpoint.
  • Detection: monitor registry for newly registered packages whose names match developers’ aborted install attempts in your fleet (good signal of attempted slopsquat).

References