Skip to content

lakeforestcomputer-com/wp-tarpit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wp-tarpit

A lightweight honeypot that wastes WordPress scanners' time by slowly dripping an endless fake database dump.

Instead of returning a fast 404 to bots probing for /wp-login.php, /wp-admin/, /xmlrpc.php, etc., wp-tarpit responds with HTTP 200 and streams a never-ending fake SQL backup full of convincing-looking (but completely fake) credentials. Each response takes 30+ seconds and ties up the scanner's connection, making your server an expensive target to probe.

WARNING: Do not install this on sites that actually run WordPress. wp-tarpit intercepts all requests to /wp-admin, /wp-login.php, /xmlrpc.php, etc. and traps them. This is designed for non-WordPress sites where those paths would normally return 404. Installing it on a real WordPress site will lock out admins and break the application.

How it works

Scanner ──► nginx/Apache ──► wp-tarpit (Unix socket)
               │                   │
               │  /wp-login.php    │  200 OK
               │  ────────────►    │  Content-Type: application/sql
               │                   │
               │                   │  -- WordPress Database Backup
               │                   │  INSERT INTO wp_users ...
               │                   │  'sk_live_a3f8...' ← (fake)
               │                   │  ... (drip, drip, drip)
               │                   │
               │  /about (normal)  │
               │  ────────────►    │  (not intercepted — passes to your real backend)
  • Runs as a hardened systemd service under a dedicated no-login user
  • Communicates via Unix socket (no TCP port exposure)
  • Zero dependencies — Python 3.7+ standard library only
  • Systemd security score: 1.2/10 (lower is better)
  • Works with any backend — your real application is unaffected

Quick start

git clone https://github.com/lakeforestcomputer-com/wp-tarpit.git
cd wp-tarpit
sudo bash scripts/install.sh

The installer will:

  1. Create a wp-tarpit system user (no home, no shell)
  2. Deploy the script to /opt/wp-tarpit/
  3. Scan the host for .env files and automatically build a SHA-256 blacklist of your real secrets
  4. Install and start the systemd service
  5. Detect Apache or nginx and install the appropriate snippet
  6. Add the web server user to the wp-tarpit group for socket access

Then add the snippet to your virtual hosts:

Apache — add before any ProxyPass / directive:

<VirtualHost *:443>
    Include /etc/apache2/snippets/wp-tarpit.conf

    ProxyPass / http://your-backend:8000/
    ProxyPassReverse / http://your-backend:8000/
</VirtualHost>

nginx — add inside each server {} block:

server {
    include snippets/wp-tarpit.conf;

    location / {
        proxy_pass http://your-backend:8000;
    }
}

Restart your web server and you're done.

Verify it works

# Direct socket test (should drip slowly and return fake SQL)
curl --unix-socket /run/wp-tarpit/wp-tarpit.sock --max-time 5 http://localhost/test

# Through your web server
curl -sk --max-time 10 https://yoursite.com/wp-login.php

# Check logs
journalctl -u wp-tarpit -f

Blacklist: protect your real secrets

wp-tarpit generates random hex and alphanumeric strings. The odds of accidentally generating one of your real API keys are astronomically small (1 in 16^64 for a 64-character hex string), but you can eliminate even that possibility.

The blacklist file stores SHA-256 hashes of your real secrets — never the plaintext values. The tarpit checks each generated string against the blacklist before sending it.

During installation, the installer automatically scans /etc, /opt, /srv, /home, /var/www, and /root for .env files and builds the initial blacklist. To update it later or add additional sources:

Regenerate or extend the blacklist

Scan directories for .env files:

sudo bash scripts/generate-blacklist.sh -d /etc -d /opt -d /srv

Scan specific files:

sudo bash scripts/generate-blacklist.sh \
    -f /etc/myapp/.env \
    -f /opt/app/config.env

Add individual secrets:

sudo bash scripts/generate-blacklist.sh \
    -s "sk_live_abc123..." \
    -s "whsec_xyz789..."

Combine all approaches:

sudo bash scripts/generate-blacklist.sh \
    -d /etc/myapp \
    -f /home/deploy/.env \
    -s "my-specific-api-key"

Then restart the service:

sudo systemctl restart wp-tarpit

What the blacklist contains

The blacklist file at /opt/wp-tarpit/blacklist.sha256 looks like this:

a3f8b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5
...

Each line is a SHA-256 hash. An attacker who obtains this file gains nothing — the hashes cannot be reversed to recover your secrets.

Configuration

The service accepts command-line arguments. Edit the systemd unit's ExecStart line to customize:

Option Default Description
--socket /run/wp-tarpit/wp-tarpit.sock Unix socket path
--blacklist /opt/wp-tarpit/blacklist.sha256 Blacklist file path
--delay-min 0.5 Minimum delay between chunks (seconds)
--delay-max 2.0 Maximum delay between chunks (seconds)
--max-connections 50 Maximum concurrent tarpit connections
--max-session 300 Maximum session duration in seconds

Example — slow the drip to 2-5 seconds per chunk:

ExecStart=/usr/bin/python3 /opt/wp-tarpit/wp-tarpit.py --delay-min 2 --delay-max 5

Intercepted paths

By default, these WordPress paths are routed to the tarpit:

Path Why
/wp-admin/* Admin panel — #1 scanner target
/wp-login.php Login page — brute force target
/wp-config.php Config file — contains DB creds
/xmlrpc.php XML-RPC — amplification attacks
/wp-content/* Plugins/themes — vulnerability scanning
/wp-includes/* Core files — version fingerprinting
/wordpress/* Common path guess by scanners

Edit the web server snippet to add or remove paths.

Security model

Privilege isolation

Layer Protection
User Dedicated wp-tarpit system user — no home, no shell, own group
Filesystem Script: 500, blacklist: 400, directory: 500 — all owned by wp-tarpit
Network Unix socket only (RestrictAddressFamilies=AF_UNIX) — no TCP/UDP
Kernel NoNewPrivileges, ProtectSystem=strict, PrivateDevices, MemoryDenyWriteExecute, ProtectKernel*
Syscalls Allowlist via SystemCallFilter, no privileged/mount/resource calls
Capabilities CapabilityBoundingSet= (empty — zero capabilities)
Blacklist SHA-256 hashes only — no plaintext secrets stored

Run systemd-analyze security wp-tarpit to audit the sandbox yourself.

DoS protection

The tarpit is designed to waste attacker resources, not yours. Multiple layers prevent it from being turned against you:

Layer What it does Default
Web server rate limit nginx limit_req / Apache mod_ratelimit throttles requests per IP before they reach the tarpit 2 req/s (nginx), 512 bytes/s (Apache)
Connection cap Tarpit drops new connections beyond the limit immediately 50 concurrent
Session timeout Each connection is terminated after a maximum duration 300 seconds
systemd memory limit OOM-kills the tarpit if it exceeds the cap 128 MB
systemd CPU quota Prevents the tarpit from starving other services 25% of one core
systemd file descriptors Hard cap on open sockets 256
systemd task limit Hard cap on threads 128

What scanners see

A bot hitting /wp-login.php receives:

-- WordPress Database Backup
-- Generated by WP-CLI v2.11.0
-- Host: localhost
-- Database: wordpress_production

INSERT INTO `wp_stripe_customers` (`sk_live_key`, `option_name`, `api_secret`, `id`, `meta_key`) VALUES
('b6a52583d962375585a061466839ef952c20f5f4ad913d19a9c32382b98154a2', ...),
('95f0293919519e996df77449c03a15633e55ea11d532e2446fc005af10aab217', ...),
...

The response never ends. New INSERT statements keep appearing every 0.5-2 seconds, each packed with fake hex strings that look like API keys and credentials. The scanner's connection stays pinned, wasting its time and resources.

Uninstall

sudo bash scripts/uninstall.sh
# Then restart your web server
sudo systemctl restart apache2  # or nginx

Requirements

  • Python 3.7+
  • systemd
  • Apache (with mod_rewrite, mod_proxy, mod_proxy_http) or nginx
  • Linux

License

MIT — see LICENSE.

About

A lightweight honeypot that wastes WordPress scanners' time by streaming an endless fake SQL dump

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors