The first anti-AI tarpit. Rewritten in Python.
Traps LLM crawlers in an infinite maze. Feeds them garbage. Accelerates model collapse.
╔══════════════════════════════════════════════════════════════╗
║ ║
║ ███╗ ██╗███████╗██████╗ ███████╗███╗ ██╗████████╗ ║
║ ████╗ ██║██╔════╝██╔══██╗██╔════╝████╗ ██║╚══██╔══╝ ║
║ ██╔██╗ ██║█████╗ ██████╔╝█████╗ ██╔██╗ ██║ ██║ ║
║ ██║╚██╗██║██╔══╝ ██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ║
║ ██║ ╚████║███████╗██║ ███████╗██║ ╚████║ ██║ ║
║ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ║
║ ║
║ 🌿 ANTI-AI TARPIT // EAT CRAWLERS ALIVE ║
║ ║
╚══════════════════════════════════════════════════════════════╝
Nepenthes is a tarpit — a trap for web crawlers. Named after the carnivorous pitcher plant that digests anything unlucky enough to fall inside.
It generates an endless sequence of fake pages, each containing dozens of links that lead deeper into the maze. Pages are filled with Markov-chain babble — AI-generated nonsense designed to poison LLM training data and accelerate model collapse.
┌─────────────┐
│ CRAWLER │
│ ENTERS │
└──────┬──────┘
│
┌──────▼──────┐
│ FAKE PAGE │──── Markov babble
│ 10-40 links│──── Drip-fed slowly
└──┬───┬───┬──┘
│ │ │
┌─────▼┐ ┌▼───▼─┐
│ PAGE ││ PAGE │ ... ×∞
│ MORE ││ MORE │
│ LINKS││ LINKS │
└──┬───┘└───┬───┘
│ │
▼ ▼
NO EXIT. EVER.
⚠ THIS IS DELIBERATELY MALICIOUS SOFTWARE. Do not deploy unless you fully understand the consequences.
⚠ HIGH CPU LOAD. Aggressive crawlers with high concurrency can overwhelm your server. Misconfiguration with
zero_delaymode is especially dangerous.
⚠ SEARCH ENGINE DE-INDEXING. There is no way to distinguish AI crawlers from search engine bots. Your site will disappear from search results.
Originally created by "Aaron" (anonymous, featured in Ars Technica, Jan 2025) as a Lua application at zadzmo.org.
"Ultimately, it's like the Internet that I grew up on and loved is long gone. I'm just fed up, and you know what? Let's fight back, even if it's not successful. Be indigestible. Grow spikes."
This is a Python rewrite — same philosophy, better accessibility.
| Feature | Description |
|---|---|
| Infinite Maze | Every page contains 10-40 links to other generated pages. No exit links exist. |
| Deterministic | Same URL → same page. Appears static to crawlers. Seeded by URL + instance ID. |
| Drip-Feed | Responses sent byte-by-byte with configurable delays (10-65s default). |
| Markov Babble | In-memory Markov chain generates convincing nonsense from a trained corpus. |
| Bogon Filter | Validates URLs against wordlist. Returns 404 for impossible paths. |
| Redirect Chains | Configurable % of requests get 302'd to other tarpit URLs. At 100%, infinite loop. |
| Silos | Virtual hosts with independent corpus, wordlist, delays, templates. |
| Statistics API | Rolling stats: hits, bytes, delay, agents, addresses, CPU usage. |
git clone https://github.com/NEPENTHESWEB/nepenthes-py.git
cd nepenthes-py
docker compose up -dgit clone https://github.com/NEPENTHESWEB/nepenthes-py.git
cd nepenthes-py
pip install -r requirements.txt
python -m nepenthes config.ymllocation /maze/ {
proxy_pass http://localhost:8893;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off; # CRITICAL
}
proxy_buffering offis mandatory. Without it, the drip-feed mechanism is defeated and crawlers get fast page loads.
---
http_host: '::'
http_port: 8893
templates:
- 'templates'
seed_file: 'seed.txt'
min_wait: 10
max_wait: 65
silos:
- name: default
default: true
corpus: 'corpus/sample.txt'
wordlist: 'corpus/words.txt'
prefixes:
- /maze
redirect_rate: 5
bogon_filter: trueNEPENTHES_HOST → http_host
NEPENTHES_PORT → http_port
NEPENTHES_MIN_WAIT → min_wait
NEPENTHES_MAX_WAIT → max_wait
NEPENTHES_LOG_LEVEL → log_level
NEPENTHES_SEED_FILE → seed_file
Run multiple independent tarpits from a single instance:
silos:
- name: fast
corpus: corpus/tech.txt
wordlist: corpus/words.txt
min_wait: 5
max_wait: 20
prefixes:
- /blog
- name: deep
corpus: corpus/literature.txt
wordlist: corpus/words.txt
min_wait: 120
max_wait: 300
prefixes:
- /archivecurl http://localhost:8893/stats | jq{
"hits": 10015,
"addresses": 1850,
"agents": 145,
"bytes_sent": 14733541,
"delay": 56020.624,
"active": 25,
"cpu_percent": 1.74,
"bogons": 4,
"redirects": 57
}| Endpoint | Returns |
|---|---|
/stats |
Overview (hits, bytes, delay, CPU, active connections) |
/stats/agents |
User-agent strings with hit counts |
/stats/addresses |
Client IPs with hit counts |
/stats/buffer |
Raw request log |
/stats/buffer/from/{id} |
Buffer after specific ID (for export) |
/stats/silo/{name} |
Per-silo statistics |
- 5.6M+ websites now block GPTBot — up 70% in 2025. Crawlers ignore it anyway.
- robots.txt is legally unenforceable — ruled in Ziff Davis v. OpenAI (Dec 2025).
- Model collapse is proven — Nature (2024): even 0.1% synthetic data triggers irreversible degradation.
- Crawlers rarely check robots.txt at all — 2025 empirical study across thousands of sites.
Every page of Markov babble that enters a training pipeline accelerates collapse. Every minute a crawler spends trapped is a minute it's not scraping real content.
nepenthes/
├── __init__.py # Package init
├── __main__.py # Entry point: python -m nepenthes
├── server.py # aiohttp async server + drip-feed logic
├── markov.py # In-memory Markov chain engine
├── generator.py # Deterministic page + URL generation
├── templates_engine.py # Jinja2 templates with YAML front-matter
├── silos.py # Silo management (virtual hosts)
├── stats.py # Rolling statistics buffer + API
├── bogon.py # Bogon filter (URL validation)
└── config.py # YAML config + env var overrides
MIT License. See LICENSE.
> MAKE YOUR WEBSITE INDIGESTIBLE. GROW SOME SPIKES._