In January 2026, OpenClaw disclosed CVE-2026-25253 — a remote code execution vulnerability that exposed over 135,000 publicly accessible instances due to lax default configurations. If your OpenClaw deployment (whether npm, Docker, or VPS) has not passed a security baseline audit, now is the time to harden it. This article walks through the incident recap, three deployment-specific hardening checklists (Docker, systemd/VPS, npm global), and a 5-stage vulnerability response playbook (detect → backup → upgrade → verify → 72h monitoring) to transform your agent from "it works" to "battle-tested."
In mid-January 2026, the OpenClaw security team disclosed CVE-2026-25253: when Gateway runs with default configuration (listening on 0.0.0.0 without authentication), an attacker can achieve remote code execution via a crafted WebSocket handshake. Shodan scans revealed over 135,000 instances accessible without authentication — spanning personal developers, small teams, and enterprises with misconfigured tunneling.
The root cause was not a code bug but overly permissive defaults:
0.0.0.0; without a firewall or reverse-proxy auth, this exposes the management port to the entire internet.OPENCLAW_GATEWAY_TOKEN or TLS, leaving clear-text channels vulnerable to MITM.openclaw onboard on a VPS and considered deployment complete, skipping subsequent gateway.bind tightening and ufw rules.The incident prompted official changes starting in v2026.2.0: default bind address switched to 127.0.0.1, and the installer now includes mandatory security checks. However, existing instances still require manual remediation — this article provides the actionable checklist.
Regardless of deployment type, all three must hold simultaneously:
OPENCLAW_GATEWAY_TOKEN (≥32 characters, rotated every 90 days).If you run OpenClaw via Docker / Docker Compose, audit each item below:
| Checklist Item | Secure Configuration | Dangerous Example | Remediation Command / Step |
|---|---|---|---|
| network_mode | Custom bridge or host with restricted port mapping | ports: "0.0.0.0:18789:18789" | Change to 127.0.0.1:18789:18789 or route via reverse proxy only |
| --read-only | Container root filesystem read-only; volumes explicitly listed | Missing read_only: true | Add read_only: true to Compose; ensure ./openclaw-data:/home/node/.openclaw volume mounts present |
| User & volume permissions | Run as non-root (node:1000); host volume UID/GID match | Container root, host dir 755宽松 | user: "1000:1000"; pre-chown 1000:1000 volume directories |
| Restart policy | unless-stopped or on-failure:3 | No restart policy (container exits on crash) | Ensure self-healing; combine with healthcheck |
| OPENCLAW_GATEWAY_TOKEN | Injected via environment; length ≥32; matches CLI config | Empty token or hardcoded in image | environment: OPENCLAW_GATEWAY_TOKEN=${TOKEN}; also set on host via openclaw config set gateway.token $TOKEN |
After changes, verify with docker exec <container> netstat -tlnp that Gateway listens only on 127.0.0.1:18789 (or your reverse-proxy port).
When running OpenClaw as a systemd service on a VPS, enforce the following firewall and OS-level controls:
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp # SSH sudo ufw allow 443/tcp # HTTPS (if reverse proxy) sudo ufw allow 80/tcp # HTTP (optional, redirect to HTTPS) sudo ufw enable
sudo ufw status numbered # Should show no rule allowing 18789/tcp
PasswordAuthentication noOpenClaw logs default to /tmp/openclaw/openclaw-YYYY-MM-DD.log. Configure logrotate to prevent disk exhaustion:
# /etc/logrotate.d/openclaw
/tmp/openclaw/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
}
[Unit]
Description=OpenClaw Gateway
After=network.target
[Service]
Type=simple
User=node
Group=node
ExecStart=/usr/bin/openclaw gateway start
ExecStop=/usr/bin/openclaw gateway stop
Restart=on-failure
RestartSec=5
# Security hardening
PrivateTmp=yes
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/home/node/.openclaw /var/log/openclaw
Environment="OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}"
# Optional resource limits
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
For local npm installs (common on dev boxes or manual ops), you must tighten the Gateway bind address:
# Force Gateway to listen on 127.0.0.1 only openclaw config set gateway.bind 127.0.0.1 # Verify openclaw config get gateway.bind # Should output 127.0.0.1
If external access is required, pair with a reverse proxy (Nginx/Caddy) using HTTP basic auth or OAuth:
location /openclaw/ {
proxy_pass http://127.0.0.1:18789/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Basic auth (example)
auth_basic "OpenClaw Admin";
auth_basic_user_file /etc/nginx/.htpasswd;
# Or integrate OAuth2 proxy
openclaw --version. If < 2026.2.0 and Gateway is internet-facing, mark as high-risk immediately.nmap -p 18789 <your-public-ip> to confirm port accessibility.~/.openclaw/: tar -czf openclaw-backup-$(date +%F).tar.gz ~/.openclawopenclaw gateway export > gateway-state.jsonnpm update -g openclaw or docker pull openclaw/openclaw:latestgateway.bind to 127.0.0.1; ensure reverse proxy has TLS + auth enabled.openclaw gateway token rotate; update all CLI instances and CI env vars.openclaw gateway restartopenclaw gateway status should show "healthy"openclaw logs --follow | grep -i errorRun this checklist monthly to ensure your OpenClaw instance has not drifted into an insecure state:
| Category | Check Command / Action | Pass Criteria | Fail Remediation |
|---|---|---|---|
| Ports | ss -tlnp | grep 18789 | Listen address = 127.0.0.1 | openclaw config set gateway.bind 127.0.0.1 + restart |
| Authentication | openclaw config get gateway.token (length & age) | Token ≥32 chars, rotated <90 days ago | openclaw gateway token rotate; update all dependents |
| Logs | du -sh /tmp/openclaw/ + logrotate status | Log dir <500MB, logrotate active | Adjust logrotate config; prune old logs |
| Updates | openclaw --version vs latest release | Version ≥ 2026.2.0 (latest stable) | npm update -g openclaw or docker pull |
| Backups | Check ~/.openclaw/backup/ for archives <7 days old | Full backup exists within last 7 days | Run openclaw backup immediately |
openclaw/openclaw:latest, :2026.3.13, :stable.Many teams adopt a "just get it running" mindset during PoC or temporary deployments, skipping firewall config, token rotation, and log rotation. This might save 15 minutes on a dev box but introduces three fatal risks in production:
Security hardening is step one, not an afterthought. For production OpenClaw workloads requiring stability and longevity, MACCOME's managed offering includes all baselines out-of-the-box (auto token rotation, firewall whitelisting, 24/7 intrusion monitoring) — so you can use OpenClaw without self-hosting headaches. If you choose self-hosting, audit every item in this checklist and record the results in your team's operations manual.
FAQ
My OpenClaw is on v2026.1.0 — am I definitely vulnerable to CVE-2026-25253?
Affected versions are <2026.2.0, but exploitation only works if Gateway is directly exposed (no reverse proxy or firewall). Even if your version matches, binding to 127.0.0.1 or using a controlled tunnel reduces risk significantly. Upgrade and tighten bind address regardless.
I already set read_only: true in Docker Compose — is a firewall still needed?
Yes. Read-only prevents container file modification, but the Gateway port may still be accessible externally. Full hardening requires: read-only + bind 127.0.0.1 + reverse-proxy auth.
Does token rotation disconnect existing channels (Telegram/Slack)?
Yes. Gateway token is the CLI ↔ Gateway credential; rotation forces all connected CLI/Agents to re-pair. Channel-level tokens (e.g., Telegram bot token) are unaffected.
What if production must expose Gateway externally? How to apply least privilege?
Least privilege = (Gateway listens localhost only) + (reverse proxy enforces TLS + auth) + (source IP whitelist where feasible). The proxy layer (Nginx/Caddy/Traefik) should live in a separate container or edge node, forwarding only authenticated requests to 127.0.0.1:18789.
How do I check if my instance has already been compromised?
Look for: 1) Unknown CLI tokens in openclaw config list; 2) Connection logs from unfamiliar IPs in ~/.openclaw/logs/; 3) Suspicious child processes (curl/wget outbound). If any appear, isolate immediately, backup, and rebuild from scratch.