slopcatch
Flags AI-hallucinated package names in manifests and imports before you pip or npm install.
Links
README
From the repo.
slopcatch
Open-source slopsquat guard — flags AI-hallucinated package names in manifests and imports before you pip or npm install. Offline, zero dependencies.
git clone https://github.com/JaydenCJ/slopcatch && cd slopcatch && pip install -e .
Pre-release: slopcatch is not yet published to PyPI. Until the first release, clone JaydenCJ/slopcatch and run
pip install -e .from the repository root.
Why slopcatch?
Slopsquatting is the 2025-vintage supply-chain attack with the simplest possible mechanic: code assistants hallucinate package names, the hallucinations recur across prompts and models, and attackers register them before you read the diff. Researchers measured roughly a fifth of AI-recommended packages resolving to nothing — or worse, to whoever claimed the name first. The existing tooling attacks the wrong half of the problem: typosquat scanners score keyboard distance to popular names, but a model never fat-fingers reqeusts — it composes openai-sdk, transplants axios into requirements.txt, or upgrades pip install cv2 from import name to install command. slopcatch is a single-purpose checker aimed at exactly those generation patterns: seven rules, an embedded corpus, no network, no account, exit code 2 before the installer runs.
| slopcatch | Socket | GuardDog | typosquat scanners | |
|---|---|---|---|---|
| Detects hallucination patterns (composition, not typos) | yes — 7 dedicated rules | no | no | no |
Import-name vs install-name traps (cv2, yaml, PIL) | yes, with the real name | no | no | no |
Cross-ecosystem transplants (axios in requirements.txt) | yes | no | no | no |
| Works fully offline | yes (embedded corpora) | no (SaaS API) | no (fetches packages + rules) | mostly |
| Flags names that do resolve on the registry | yes — registered slop is worse | reputation-based | scans the tarball | no (existence = pass) |
| Runtime dependencies | 0 | app + CLI + API key | Python, Semgrep, pip tree | varies |
Column facts checked against Socket and GuardDog public docs, 2026-07. Both do far more than name checks — slopcatch deliberately does this one thing, before anything is downloaded.
Features
- Exit code as a gate —
slopcatch check requirements.txtexits 2 the moment any finding reaches--fail-level(default: high), so a one-line hook blockspip install; 0 means go, 1 means you held it wrong. - Hallucination patterns, not string distance — suffix echoes (
openai-sdk), prefix echoes (python-requests), version drift (beautifulsoup), ecosystem transplants (expresson PyPI), template names (smart-json-parser-tools), and a seed list of documented slop. - The pip trap, named — 35 import-name→distribution mappings turn
pip install cv2into "did you mean: opencv-python" instead of a mystery package. - Scans what you actually have — package.json (all four dependency sections), requirements/constraints files, pyproject.toml (PEP 621, poetry, build-system; works without tomllib on 3.9), plus
ast-parsed Python and JS/TS import scanning. - Allowlist, not gag order —
--allow/--allow-filesuppress a finding but report the name asallowed, so the JSON stays honest about why nothing fired; unknown names are reported, never flagged. - Zero everything — zero runtime dependencies, zero network calls, zero telemetry; the corpora ship inside the wheel and results are deterministic byte-for-byte.
Quickstart
Install:
git clone https://github.com/JaydenCJ/slopcatch && cd slopcatch && pip install -e .
Save this as requirements.txt — two of these five packages are real:
fastapi
openai-sdk
python-dotenv
beautifulsoup
smart-json-parser-tools
Check it before installing (output copied from a real run):
$ slopcatch check requirements.txt
requirements.txt (pypi, 5 names)
HIGH openai-sdk suffix-echo: real package "openai" + generated suffix "-sdk" — the real project publishes as "openai" [line 2]
did you mean: openai
MEDIUM beautifulsoup version-drift: the registered package is "beautifulsoup4" — the un-versioned "beautifulsoup" is a common model mis-remembering [line 4]
did you mean: beautifulsoup4
MEDIUM smart-json-parser-tools template-name: assembled entirely from generic filler words (smart, json, parser, tools) — a template-shaped name typical of generated code [line 5]
checked 5 names: 2 known, 0 unknown, 0 allowed, 3 flagged (1 high, 2 medium, 0 low)
Exit code 2 — wire it straight into a pre-install hook. Single names work too, including the classic pip trap:
$ slopcatch name cv2
<names> (pypi, 1 name)
HIGH cv2 import-alias: "cv2" is the *import* name; the installable distribution is "opencv-python" [argument]
did you mean: opencv-python
checked 1 name: 0 known, 0 unknown, 0 allowed, 1 flagged (1 high, 0 medium, 0 low)
Or scan the generated source directly — slopcatch check bot.py app.ts evaluates every third-party import as if it were about to be installed. A full "vibe-coded" project lives in examples/.
Detection rules
| Rule | Severity | Catches | Example |
|---|---|---|---|
known-slop | high | Documented assistant hallucinations (seed list) | huggingface-cli |
import-alias | high | Import name used as install name | cv2 → opencv-python |
cross-ecosystem | high | Real package from the other registry | axios in requirements.txt |
prefix-echo | high | Ecosystem prefix on a real name | python-requests |
suffix-echo | high / medium | Real package / brand + glue suffix | openai-sdk, supabase-utils |
version-drift | medium | Version digits dropped or invented | beautifulsoup, psycopg3 |
template-name | medium | 3+ tokens, all generic filler | smart-json-parser-tools |
A name found in the embedded real-package corpus is never flagged, and a name matching no rule is reported as unknown, never flagged — absence from a bundled list is not evidence. Full semantics, severity rationale, and tuning notes are in docs/detection-rules.md.
| Flag | Default | Effect |
|---|---|---|
--fail-level | high | Lowest severity that makes the exit code 2 |
--format | text | text or json (versioned schema, sorted keys) |
--allow / --allow-file | — | Suppress findings for vetted names; reported as allowed |
--ecosystem | pypi | Registry for bare name checks (pypi, npm) |
--show-all | off | Also list known/unknown/allowed names in text output |
Verification
This repository ships no CI; every claim above is verified by local runs. Reproduce them from a checkout of this repository:
pip install -e '.[dev]' && pytest && bash scripts/smoke.sh
Output (copied from a real run, truncated with ...):
89 passed in 0.58s
...
SMOKE OK
Architecture
flowchart LR
M[package.json / pyproject.toml / requirements.txt] --> P[Manifest parsers]
S[.py / .ts sources] --> I[Import scanners]
P --> E[Rules engine<br/>7 hallucination patterns]
I --> E
D[(Embedded corpora<br/>real pkgs · aliases · slop seed)] --> E
E --> R[Reports: text + JSON]
R --> X{exit 0 / 2}
Roadmap
- Seven-rule engine, embedded corpora, four manifest formats, Python/JS import scanning, allowlists, text+JSON reports, CLI (v0.1.0)
- Lockfile scanning (package-lock.json, poetry.lock, uv.lock) with dependency provenance
- Go, Rust, and Ruby ecosystems (go.mod, Cargo.toml, Gemfile)
- Optional registry cross-check mode (opt-in network) reporting registration dates for flagged names
- PyPI release with
pip install slopcatch
See the open issues for the full list.
Contributing
Contributions are welcome — start with a good first issue or open a discussion. See CONTRIBUTING.md for the development setup.
License
Collected info
- ★ 0 stars
- Language: Python
- Source updated: 8/8/2026
Config for your environment
Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.
Tool
OS
Config file: ~/.cursor/mcp.json
{
"mcpServers": {
"mcp-server": {
"url": "{MCP_ENDPOINT_URL}"
}
}
}Paste into mcpServers in the config file. Restart Cursor after saving.
If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.