
High-interaction honeypot mimicking a vulnerable Laravel/Livewire app. Captures RCE exploits and webshells targeting CVE-2024-47823, CVE-2025-54068, and CVE-2025-14894, then analyzes them in sandboxed Docker containers to extract IOCs.
A high-interaction honeypot that masquerades as a vulnerable Laravel/Livewire application. It captures exploit attempts targeting known Livewire CVEs, stores uploaded malicious files (webshells) and remote code execution (RCE) payloads with SHA-256 deduplication, and optionally executes them in a sandboxed Docker container to extract indicators of compromise (IOCs) — URLs, IPs, and domains that the malware tries to contact.
The system runs as two separate processes for security: a web server that captures payloads (no Docker access) and a sandbox worker that analyzes them in isolated containers.
Attacker → Nginx → FastAPI → SQLite ← Sandbox Worker (Docker)
(capture) (polls jobs, writes IOCs)
Facade — Serves realistic Laravel login/register pages with Livewire wire: attributes, XSRF tokens, and X-Powered-By: PHP/8.3.12 headers. Automated scanners see what looks like a real vulnerable app.
Capture — Every HTTP request is logged to SQLite (IP, headers, body hash, timestamp) by an ASGI middleware layer, transparently, before any routing happens.
Traps — Livewire endpoints accept file uploads and component messages just like the real framework would. Payloads are classified (PHP code, serialized objects, shell commands) and stored with SHA-256 deduplication. Each interesting payload creates a durable job in the sandbox_jobs queue.
Sandbox — A separate worker process polls for pending jobs and executes each payload in an ephemeral Docker container (read-only filesystem, no network, cap_drop=ALL). An LD_PRELOAD shim intercepts libc network calls to log C2 (command-and-control) communication attempts. The analyzer extracts IOCs and scores potential C2 endpoints using heuristics.
A *.php catch-all trap also captures post-exploitation probing for common webshell filenames (e.g. accesson.php, wp-login.php, admin.php).
Prerequisites: Python 3.11+ and uv.
git clone https://github.com/HelgeSverre/livewire-honeypot.git
cd livewire-honeypot
# Install dependencies
uv sync
# Start the web server (capture-only, no Docker needed)
DATA_DIR=./data uv run uvicorn honeypot.main:app --reload --port 8000
# In a second terminal — start the sandbox worker (requires Docker)
DATA_DIR=./data uv run python -m honeypot.worker
# Run tests
uv run pytest tests/ -v
The web server works standalone — it captures and stores everything even without the sandbox worker running. Start the worker when you want automated payload analysis.
Note: The
src/directory is on the Python path viapyproject.toml(src-layout), sohoneypot.main:appmaps tosrc/honeypot/main.py.
You will need:
The full deploy is a single command once the VPS exists. The script handles every step from "bare droplet" to "service running with TLS" — apt packages, users and groups, Python venv, sandbox image, nginx, certbot, and firewall rules.
# 1. Provision a $6/mo droplet (Ubuntu 24.04, 1 GB RAM is enough).
# On DigitalOcean:
doctl compute droplet create veritron-honeypot \
--size s-1vcpu-1gb \
--image ubuntu-24-04-x64 \
--region fra1 \
--ssh-keys "$(doctl compute ssh-key list --format ID --no-header | head -1)" \
--wait
# 2. Point your domain's A record at the droplet IP.
# Wait for DNS to resolve before continuing.
dig +short your-domain.example # should return the droplet IP
# 3. Copy the project onto the droplet.
rsync -az --exclude='.git' --exclude='.venv' --exclude='data' \
./ root@<droplet-ip>:/opt/honeypot/
# 4. Run the bootstrap script. Passing your domain enables TLS via certbot.
ssh root@<droplet-ip> 'cd /opt/honeypot && [email protected] \
bash deploy/setup.sh your-domain.example'
That's it. The honeypot is now serving a fake Laravel/Livewire login page over HTTPS, capturing every request to SQLite, and ready to analyse payloads in the Docker sandbox.
deploy/setup.sh is idempotent — re-running it is safe. In order, it:
honeypot (web) and sandbox (worker) service users, plus the shared honeypot-data group.uv sync --python /usr/bin/python3.12. We deliberately use the apt-installed Python rather than uv's bundled interpreter — uv's Python lives in /root/.local/share/uv/, which an unprivileged service user cannot traverse, and you get a confusing status=203/EXEC from systemd if you let uv pick the interpreter./var/honeypot/ with setgid bit and shared group ownership, so both services can read each other's writes.ExecStart to use the system Docker daemon (the shipped unit assumes rootless Docker, which is harder to set up).docker build -t honeypot-sandbox sandbox/).limit_req_zone directive into (it must be in the block, not in ).If you want to drive each step yourself instead of running setup.sh, the equivalent shell history lives in deploy/setup.sh as commented stages.
| Service | User | Purpose | Docker Access |
|---|---|---|---|
honeypot.service |
Both services share /var/honeypot/ for the SQLite database and payload storage. The web process has no Docker socket access, so even if compromised through attacker traffic, it cannot create containers on the host.
# View logs
journalctl -u honeypot -f
journalctl -u honeypot-worker -f
# Restart services
systemctl restart honeypot honeypot-worker
# Upgrade
cd /opt/honeypot && git pull && uv sync
docker build -t honeypot-sandbox sandbox/
systemctl restart honeypot honeypot-worker
All settings are controlled via environment variables (set in the systemd unit files or exported before running):
All data lives in a single SQLite database (default: /var/honeypot/captures.db).
# Recent requests
sqlite3 /var/honeypot/captures.db \
"SELECT timestamp, source_ip, method, path, matched_trap
FROM requests ORDER BY id DESC LIMIT 20;"
# Unique payloads by frequency
sqlite3 /var/honeypot/captures.db \
"SELECT sha256, filename, payload_type, times_seen, sandbox_status
FROM payloads ORDER BY times_seen DESC;"
# Top attacker IPs
sqlite3 /var/honeypot/captures.db \
"SELECT ip, total_requests, first_seen, last_seen
FROM attackers ORDER BY total_requests DESC LIMIT 10;"
# Sandbox results with extracted IOCs (JSON)
sqlite3 /var/honeypot/captures.db \
"SELECT payload_id, exit_code, duration_seconds, c2_urls_found, iocs
FROM sandbox_runs ORDER BY id DESC LIMIT 5;"
# Pending sandbox jobs
sqlite3 /var/honeypot/captures.db \
"SELECT id, payload_sha256, status, created_at
FROM sandbox_jobs ORDER BY id DESC LIMIT 10;"
IOC data in sandbox_runs.iocs is stored as JSON with keys: domains, ips, emails, urls, hashes. Extract and feed into your threat intel platform (MISP, OpenCTI, etc.) as needed.
src/honeypot/
main.py # FastAPI web app (capture-only, no Docker)
worker.py # Standalone sandbox worker (polls SQLite, needs Docker)
config.py # Settings from environment variables
capture/
database.py # Async SQLite — requests, payloads, sandbox_jobs queue
logger.py # ASGI middleware — logs every request
payloads.py # SHA-256 dedup storage + payload classification
facade/
routes.py # Laravel-fingerprinted pages (login, register, etc.)
templates/ # Jinja2 HTML with Livewire wire: attributes
static/ # Fake livewire.js (v3.5.1 fingerprint)
traps/
livewire.py # POST /livewire/message, /upload-file, /preview-file
php_catchall.py # Catch-all for *.php probing
sandbox/
orchestrator.py # Docker container lifecycle + hardening
analyzer.py # Artifact parsing + IOC extraction + C2 scoring
deploy/
nginx.conf # Reverse-proxy with rate limiting
honeypot.service # systemd unit (web)
honeypot-worker.service # systemd unit (sandbox worker)
setup.sh # VPS bootstrap script
sandbox/
Dockerfile # Sandbox container image (PHP 8.3 + attacker tools)
entrypoint.sh # Container entry-point with LD_PRELOAD network shim
This is a research tool for collecting malware samples and observing attacker behavior on infrastructure you own. It is not a production security product. Deploy only on systems you control, and be aware that capturing and executing attacker payloads may have legal implications in your jurisdiction. The SQLite database and payload files grow unbounded — monitor disk usage and implement retention policies as needed.
Issues and pull requests are welcome.
| CVE | CVSS | Summary | Trap Endpoint |
|---|
| CVE-2024-47823 | 9.8 Critical | Livewire file upload RCE via MIME type bypass. File extensions are guessed from MIME type instead of validated from the filename, allowing .php uploads disguised as images. Affects Livewire < 2.12.7 and < 3.5.2. | POST /livewire/upload-file |
| CVE-2025-54068 | 9.2 Critical | Livewire prop hydration RCE. The hydration process fails to sanitize object types in component property updates, allowing injected payloads to execute server-side. Affects Livewire 3.0.0-beta.1 through 3.6.3. | POST /livewire/message |
| CVE-2025-14894 | Critical | Livewire Filemanager unrestricted upload RCE. Missing file type and MIME validation allows unauthenticated upload of executable PHP files. | POST /livewire/upload-file |
/etc/nginx/conf.d/http {}server {}certbot --nginx if a domain was passed.honeypot |
| Web server — captures requests and payloads |
| No |
honeypot-worker.service | sandbox | Sandbox worker — analyzes payloads in Docker | Yes |
| Variable | Default | Description |
|---|
DATA_DIR | /var/honeypot | Base directory for all data |
DB_PATH | $DATA_DIR/captures.db | SQLite database path |
SANDBOX_TIMEOUT | 60 | Max seconds per sandbox run |
SANDBOX_MEMORY | 128m | Container memory limit |
SANDBOX_CPUS | 0.5 | Container CPU limit |
SANDBOX_MAX_CONCURRENT | 3 | Max concurrent sandbox containers |
SANDBOX_IMAGE | honeypot-sandbox | Docker image for sandbox |
WORKER_POLL_INTERVAL | 2.0 | Seconds between job polls |