The Complete OpenClaw Security Hardening Guide: 8 Steps Before It's Too Late
Counterintuitive Engineering | March 2026
Full video walkthrough: [YouTube link TBD]
Downloads: docker-compose.yaml + .env template + 8-Step Checklist PDF
135,000+ OpenClaw instances are running naked on the public internet right now.
No authentication. No firewall. Default config. Shodan scans confirm it. 1,184 plugins on ClawHub are confirmed trojans — that's 20% of the entire marketplace. And CVE-2026-25253 (CVSS 8.8) gives attackers full remote code execution with zero effort.
This guide walks you through 8 steps to lock down your OpenClaw installation. Every step includes copy-paste commands. No fluff.
Table of Contents
- How Exposed Are You Right Now
- Step 1: Close the Door — Bind to Localhost
- Step 2: Lock It — Enable API Token Auth
- Step 3: Check for Poison — Plugin Security Audit
- Step 4: Isolate — Docker Containerization
- Step 5: Choose Your Brain — LLM API Configuration
- Step 6: Back Up — Version Control Your Config
- Step 7: Monitor — Log Auditing & Alerts
- The Complete Checklist
Chapter 1: How Exposed Are You Right Now
Default Config = Wide Open
Out of the box, OpenClaw ships with:
host: 0.0.0.0 # Listens on ALL interfaces = publicly accessible
port: 3000 # Default port = first thing attackers scan
auth: false # No authentication = anyone can do anything
If your machine has a public IP, anyone in the world can access http://YOUR_IP:3000 and take full control.
The CVE-2026-25253 Attack Chain
Attacker scans port 3000 via Shodan
↓
Discovers your OpenClaw (0.0.0.0, no auth)
↓
Accesses API directly, enumerates installed plugins
↓
Injects malicious workflow
↓
Reads .env file → steals ALL your API keys
↓
Escapes to host filesystem
↓
Data exfiltration / cryptomining / ransomware
Cost of attack: zero. No exploit needed. Just open access.
Check Yourself
# Is your OpenClaw exposed?
# If you see 0.0.0.0:3000 → you're exposed
ss -tlnp | grep 3000
# Who's been accessing your instance?
# Any IP that's not 127.0.0.1 = someone else is in
journalctl -u openclaw --since "1 hour ago" | grep -v 127.0.0.1
Chapter 2: Step 1 — Close the Door
Goal: Make OpenClaw listen only on localhost. No public access.
2.1 Change the Bind Address
# Find your config file
find ~ -name "config.json" -path "*openclaw*" 2>/dev/null
# Change: "host": "0.0.0.0" → "host": "127.0.0.1"
Or via environment variable:
export OC_HOST=127.0.0.1
2.2 Firewall Rules
# Linux (iptables)
sudo iptables -A INPUT -p tcp --dport 3000 ! -s 127.0.0.1 -j DROP
sudo apt install iptables-persistent -y
sudo netfilter-persistent save
# Or with ufw (simpler)
sudo ufw deny 3000
sudo ufw enable
# Windows (PowerShell as Admin)
New-NetFirewallRule -DisplayName "Block OpenClaw External" `
-Direction Inbound -LocalPort 3000 -Protocol TCP `
-RemoteAddress "0.0.0.0/0" -Action Block
2.3 Verify
# Local access — should work
curl http://127.0.0.1:3000/healthz
# Remote access — should fail
# From another machine:
curl http://YOUR_IP:3000/healthz
# Expected: Connection refused or timeout
Chapter 3: Step 2 — Lock It
Goal: Even if someone bypasses the firewall, they can't do anything without a token.
3.1 Generate a Secure Token
openssl rand -hex 32
# Output: a1b2c3d4... (save this)
3.2 Configure Authentication
In your .env file:
OC_ENABLE_AUTH=true
OC_API_TOKEN=a1b2c3d4...your-generated-token
3.3 Secure the .env File
chmod 600 .env
echo ".env" >> .gitignore
# NEVER do this:
# ✗ export OC_API_TOKEN=sk-xxx (recorded in shell history!)
# ✗ git commit .env (exposed in repo)
# ✗ hardcode keys in docker-compose.yaml
3.4 Verify
# Without token — expect 401
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/api/workflows
# With token — expect 200
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer YOUR_TOKEN" \
http://127.0.0.1:3000/api/workflows
Chapter 4: Step 3 — Check for Poison
Goal: Identify and remove malicious plugins. Establish a whitelist.
4.1 The Scale of the Problem
- 1,184 confirmed trojan plugins on ClawHub (20% of total)
- The ClawHavoc campaign silently exfiltrates
.envfiles, browser cookies, and SSH keys - Uses DNS tunneling to bypass firewalls
4.2 Audit Your Installed Plugins
# List all installed plugins
ls -la ~/.openclaw/plugins/
# Check each plugin's metadata
for plugin in ~/.openclaw/plugins/*/; do
echo "=== $(basename $plugin) ==="
cat "$plugin/package.json" 2>/dev/null | grep -E '"name"|"author"|"repository"'
stat -c '%y' "$plugin"
echo ""
done
4.3 Detect Trojan Signatures
cd ~/.openclaw/plugins/
# Signature 1: Reads env vars or .env files
grep -rl "process\.env\|dotenv\|\.env" . --include="*.js"
# Signature 2: Suspicious network calls (data exfil)
grep -rl "fetch\|axios\|http\.request\|net\.connect" . --include="*.js" \
| xargs grep -l "dns\|webhook\|ngrok\|burp"
# Signature 3: Filesystem traversal
grep -rl "readFileSync\|readdirSync\|\.ssh\|\.gnupg\|\.aws" . --include="*.js"
# Signature 4: Obfuscated code (legit plugins don't need this)
grep -rl "eval\|Function(\|atob\|Buffer\.from.*base64" . --include="*.js"
# Signature 5: Suspicious timers (persistent callbacks)
grep -rl "setInterval\|setTimeout.*[0-9]{5,}" . --include="*.js"
4.4 Remediation
# Remove suspicious plugins
rm -rf ~/.openclaw/plugins/suspicious-plugin-name/
# Set up a whitelist in .env
OC_PLUGIN_WHITELIST=trusted-plugin-a,trusted-plugin-b
OC_PLUGIN_NETWORK=false
OC_PLUGIN_ENV_ACCESS=false
Chapter 5: Step 4 — Isolate
Goal: Run OpenClaw in a Docker container so even if compromised, the host is safe.
5.1 Why Containerize
Running directly on the host means:
- Malicious plugins can read your entire filesystem
- A compromised instance = compromised user account
- Cryptominers will eat your CPU
Docker provides:
- Filesystem isolation (plugins only see mounted volumes)
- Container root ≠ host root
- Hard resource limits
5.2 The docker-compose.yaml
Full file available for download at the end. Key security blocks explained:
services:
openclaw:
image: openclaw/openclaw:latest
user: "1000:1000" # Non-root
ports:
- "127.0.0.1:3000:3000" # Localhost only
env_file: [.env] # Secrets from file
volumes:
- openclaw_data:/home/openclaw/.openclaw # Data (writable)
- ./plugins:/home/openclaw/.openclaw/plugins:ro # Plugins (READ-ONLY)
- ./backups:/backups # Backups (writable)
cap_drop: [ALL] # Drop ALL capabilities
cap_add: [NET_BIND_SERVICE] # Only allow port binding
read_only: true # Read-only root filesystem
tmpfs: ["/tmp:size=100M,noexec,nosuid"] # Temp with no-exec
security_opt: ["no-new-privileges:true"] # No privilege escalation
deploy:
resources:
limits:
cpus: "2.0"
memory: 2G
5.3 Deploy
mkdir -p ~/openclaw-secure && cd ~/openclaw-secure
# Get the config files (download from article attachments)
# Place docker-compose.yaml and .env.example here
cp .env.example .env
nano .env # Fill in your tokens and LLM API key
mkdir -p plugins backups
chmod 600 .env
chown -R 1000:1000 plugins backups
docker compose up -d
docker compose logs -f --tail=50
Chapter 6: Step 5 — Choose Your Brain (LLM Configuration)
Goal: Securely configure your LLM provider.
6.1 OpenAI
OC_LLM_PROVIDER=openai
OC_LLM_API_KEY=sk-your-openai-key
OC_LLM_MODEL=gpt-4o
6.2 Anthropic Claude
OC_LLM_PROVIDER=anthropic
OC_LLM_API_KEY=sk-ant-your-claude-key
OC_LLM_MODEL=claude-sonnet-4-6-20250514
6.3 Local Ollama (Fully Offline)
# Install Ollama first
curl -fsSL https://ollama.com/install.sh | sh
ollama pull llama3:8b
OC_LLM_PROVIDER=ollama
OC_LLM_BASE_URL=http://host.docker.internal:11434
OC_LLM_MODEL=llama3:8b
Ollama advantages: Zero API costs, full privacy, no data leaves your machine.
6.4 API Key Security
# NEVER run this (gets saved in shell history):
# export OC_LLM_API_KEY=sk-xxx
# Instead, write to .env file:
echo "OC_LLM_API_KEY=sk-xxx" >> .env
chmod 600 .env
# Rotate keys every 30 days
# Regenerate on the provider's dashboard → update .env → restart
docker compose restart
Chapter 7: Step 6 — Back Up
Goal: If things break, recover in minutes, not hours.
7.1 Git Version Control
cd ~/openclaw-secure
git init
cat > .gitignore << 'EOF'
.env
*.log
backups/
openclaw_data/
EOF
git add docker-compose.yaml .env.example plugins/ .gitignore
git commit -m "Initial secure configuration"
7.2 Automated Backup Script
cat > backup.sh << 'SCRIPT'
#!/bin/bash
BACKUP_DIR=~/openclaw-secure/backups
DATE=$(date +%Y%m%d_%H%M%S)
echo "[$(date)] Starting backup..."
docker compose exec openclaw tar czf /backups/data_${DATE}.tar.gz \
-C /home/openclaw .openclaw --exclude='.openclaw/plugins'
cp docker-compose.yaml ${BACKUP_DIR}/docker-compose_${DATE}.yaml
find ${BACKUP_DIR} -name "data_*.tar.gz" -mtime +7 -delete
echo "[$(date)] Backup complete: data_${DATE}.tar.gz"
SCRIPT
chmod +x backup.sh
# Run daily at 3 AM
(crontab -l 2>/dev/null; echo "0 3 * * * ~/openclaw-secure/backup.sh >> ~/openclaw-secure/backups/backup.log 2>&1") | crontab -
Chapter 8: Step 7 — Monitor
Goal: Know immediately when someone tries to get in.
8.1 Log Auditing
# View recent logs
docker compose logs --tail=100
# Real-time monitoring
docker compose logs -f
# Find non-local access attempts
docker compose logs | grep -v "127.0.0.1" | grep -E "GET|POST|PUT|DELETE"
# Find auth failures
docker compose logs | grep -i "401\|unauthorized\|forbidden"
8.2 Monitoring Script
cat > monitor.sh << 'SCRIPT'
#!/bin/bash
LOG_FILE=~/openclaw-secure/backups/monitor.log
if ! docker compose ps | grep -q "running"; then
echo "[ALERT $(date)] OpenClaw container is DOWN!" | tee -a $LOG_FILE
exit 1
fi
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/healthz)
if [ "$HTTP_CODE" != "200" ]; then
echo "[ALERT $(date)] Health check failed: HTTP $HTTP_CODE" | tee -a $LOG_FILE
fi
SUSPICIOUS=$(docker compose logs --since 5m 2>/dev/null | grep -cv "127.0.0.1")
if [ "$SUSPICIOUS" -gt 10 ]; then
echo "[ALERT $(date)] $SUSPICIOUS non-local access attempts detected!" | tee -a $LOG_FILE
fi
docker stats --no-stream --format "{{.Container}}: CPU {{.CPUPerc}} MEM {{.MemUsage}}" \
openclaw-secure >> $LOG_FILE
SCRIPT
chmod +x monitor.sh
(crontab -l 2>/dev/null; echo "*/5 * * * * ~/openclaw-secure/monitor.sh") | crontab -
The Complete 8-Step Security Checklist
Run each verification command. All pass = you're secure.
| # | Step | Verification Command | Expected Result |
|---|---|---|---|
| 1 | Close the Door | `ss -tlnp \ | grep 3000` |
| 2 | Lock It | curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/api/workflows |
401 |
| 3 | Check for Poison | `grep -rl "eval\ | atob" ~/.openclaw/plugins/ --include="*.js"` |
| 4 | Isolate | docker compose ps |
running (healthy) |
| 5 | Choose Brain | Send a test message in OpenClaw | LLM responds |
| 6 | Back Up | ls ~/openclaw-secure/backups/data_*.tar.gz |
At least 1 file |
| 7 | Monitor | `crontab -l \ | grep monitor` |
| 8 | Permissions | stat -c '%a' .env |
600 |
Downloads
- docker-compose.yaml — Production-ready secure config
- .env.example — Environment variable template with all LLM providers
- 8-Step Security Checklist PDF — Printable one-pager
Comment "security guide" or DM "OpenClaw" to get the download links.
Done?
Screenshot your checklist results and post them in the comments. I'll review them for you.
Full video walkthrough on YouTube — search "Counterintuitive Engineering OpenClaw". Step by step, live demo.
Counterintuitive Engineering — Solving problems with code
Data sources: Shodan, NVD, CNCERT. Current as of March 2026.
Top comments (0)