You’ve locked down your OpenClaw infrastructure. Isolated network. Dedicated user. Secrets manager in place. Then you realize: the gateway is still sitting on localhost:18789, waiting for someone to flip the right authentication bits.
This is where most deployments get complacent. They think local = secure. Loopback network = safe. And then an attacker gains shell access to the box, opens a browser, and owns your entire orchestration layer without entering a password.
Let’s talk about gateway authentication—the specific mechanics of token validation, password hashing, network binding, and why loopback alone is a false sense of security. By the end, you’ll understand how to configure OpenClaw’s authentication layer so that compromising the host doesn’t automatically mean compromising the gateway.
The Gateway Authentication Attack Surface
Before we configure, let’s understand what we’re defending. The OpenClaw gateway is the API surface through which dashboards, CLIs, and external integrations interact with your agent runtime. It’s the command and control layer. It’s the single point of authority for your entire agent orchestration.
An attacker with access to the gateway can:
- List running agents and extract context
- Invoke arbitrary skills with the agent’s permissions
- Read agent logs (which may contain secrets or sensitive data)
- Modify agent configuration in real-time
- Spawn new agents under their control
- Access the dashboard and manipulate orchestration
If the gateway has weak authentication, you’ve essentially handed them the keys to the kingdom. They don’t need to exploit OpenClaw itself. They just need to authenticate to the gateway and they’ve already won.
This is why gateway authentication deserves obsessive attention.
The Three Authentication Mechanisms
OpenClaw uses three overlapping authentication mechanisms. Most deployments only lock down one or two. That’s a mistake.
1. Gateway Tokens (gateway.auth.token)
This is the primary API authentication mechanism. When you configure:
gateway:
auth:
token: "your-secret-token-here"
…OpenClaw expects all API requests to include this token in the Authorization: Bearer header:
curl -H "Authorization: Bearer your-secret-token-here" \
https://automateanddeploy.com:18789/api/v1/agents
The Security Model: Token-based authentication is stateless. The gateway validates the token cryptographically (usually HMAC-SHA256) without maintaining session state. Fast, scalable, suitable for APIs.
The Problem: Token security depends entirely on:
- How strong the token is (length, entropy, randomness)
- How it’s transmitted (must be HTTPS if crossing networks)
- How it’s stored (must not appear in logs, error messages, or config version control)
- How it’s rotated (stale tokens become attack vectors)
Let’s dig into each.
Token strength: A weak token is one that’s predictable or short. You want at least 32 bytes (256 bits) of cryptographically random data. Converted to hex, that’s a 64-character string. Anything shorter is not enough.
# Generate a proper token
openssl rand -hex 32 # Outputs 64-char hex string
# Don't do this
# your-secret-token-here # Too short, not random
# Do this
# a7f3e8c4b2d9e1f6a4c7b5d9e2f4c8a1b3d6e9f2c5a8b1d4e7f9c2a5b8d1
Token transmission: Tokens are Bearer tokens. If you transmit them over HTTP (unencrypted), anyone on the network can sniff them. If you transmit them in URL parameters, they appear in server logs and browser history. Always use HTTPS, and always use the Authorization header.
Token storage: This is critical. Where do you store the token? If it’s in the config file and that file is committed to git, it’s compromised forever. If it’s in environment variables, it’s visible in /proc/[pid]/environ. If it’s in a log file, attackers can find it by searching /var/log.
Token rotation: Tokens that never expire become permanent attack vectors. If a token is leaked today, and you don’t rotate for six months, the attacker has six months of access. Rotate tokens regularly—every 24-72 hours for high-security deployments.
2. Gateway Passwords (gateway.auth.password)
For dashboard access (the web UI), OpenClaw also supports HTTP Basic Auth:
gateway:
auth:
password: "hashed-password-bcrypt-format"
The dashboard requires this password. You send it in plaintext over HTTPS, the gateway validates it against a bcrypt hash.
The Security Model: Password-based auth is stateful. The gateway maintains a session token (typically a cookie) after successful authentication. Subsequent requests use the session, not the raw password.
The Problem: Passwords are weaker than tokens if they’re human-memorized. But in an OpenClaw context, they’re usually strong random strings (32+ characters), so the weakness is in:
- Credential storage (if the config file is exposed)
- Session hijacking (if cookies are stolen or not properly secured)
- Network exposure (if Basic Auth is sent over HTTP instead of HTTPS)
Here’s something people don’t think about: if you’re using HTTP Basic Auth, the password is sent in the Authorization header in base64. Base64 is not encryption. It’s just encoding. Anyone who sees the HTTP request can decode it immediately:
# Basic auth is sent like this:
Authorization: Basic YWRtaW46cGFzc3dvcmQxMjM=
# Attacker decodes it:
echo YWRtaW46cGFzc3dvcmQxMjM= | base64 -d
# Output: admin:password123
# They've got your credentials.
This is why HTTPS is non-negotiable for Basic Auth. The password is only safe if the transport layer is encrypted.
3. Network Binding (localhost vs LAN vs Tailnet)
This is where the real subtlety lives. You can configure which networks the gateway listens on:
gateway:
host: "127.0.0.1" # Loopback only (default)
port: 18789
or
gateway:
host: "0.0.0.0" # All interfaces (dangerous)
port: 18789
or
gateway:
host: "10.0.0.5" # Specific LAN interface
port: 18789
The Security Model: Network binding is about controlling who can even reach the gateway. If it’s on loopback, only local processes can connect. If it’s on a LAN interface, anyone on that network can attempt connection. If it’s on 0.0.0.0, anyone on the internet can attempt connection.
The Problem: This is where we hit the browser-pivot attack, and it’s subtle enough that most people miss it entirely.
The Browser-Pivot Attack (Why Loopback Isn’t Enough)
Here’s the scenario:
- You’ve hardened OpenClaw beautifully. Isolated subnet, dedicated user, strong tokens, locked-down IAM. Gateway listens on
127.0.0.1:18789. - An attacker gains shell access to the box (compromised SSH key, vulnerability in another service, whatever).
- They know OpenClaw is running. They open a browser on the machine.
- They navigate to
https://automateanddeploy.com:18789. - The gateway responds. The dashboard loads.
- If the dashboard is served with authentication but the attacker is local, they can often bypass it or steal the session token from browser storage (localStorage, cookies).
This is the browser-pivot attack. Loopback network binding prevents remote attackers from reaching the gateway. It does not prevent local attackers (who already have shell access) from interacting with it.
The attacker can:
- Inspect browser storage and extract API tokens
- Use browser developer tools to make authenticated API requests
- Screenshot the dashboard and read sensitive agent context
- Open a separate terminal and use curl to interact with the API (if the token is stored in a config file)
Real-world example: An attacker has shell access. They run:
# Attacker is on the compromised box
cd /opt/openclaw
cat config.yaml | grep token
# Output: token: "a7f3e8c4b2d9e1f6a4c7b5d9e2f4c8a1b3d6e9f2c5a8b1d4e7f9c2a5b8d1"
# Now they can invoke agents
curl -H "Authorization: Bearer a7f3e8c4b2d9e1f6a4c7b5d9e2f4c8a1b3d6e9f2c5a8b1d4e7f9c2a5b8d1" \
https://automateanddeploy.com:18789/api/v1/agents/invoke \
-d '{"agent": "dangerous-skill", "params": {...}}'
They’ve compromised the gateway without even touching the network layer. The local filesystem was the attack vector.
Mitigation: Loopback binding is necessary but not sufficient. You also need:
- Disable dashboard access entirely if it’s not needed
- Require additional authentication (mTLS, OS-level permissions)
- Bind to an interface that’s only accessible via Tailscale/VPN
- Store tokens in a secure enclave, not the filesystem
- Implement OS-level process isolation (SELinux, AppArmor)
Understanding Threat Models
Before we configure, we need to understand what threat we’re actually defending against. Different deployment contexts have different threat models.
Low Threat Model (Local Dev Machine):
- You control the box entirely
- No untrusted code runs on it
- Network is your home WiFi or isolated dev lab
- Risk: Accidentally exposing credentials, careless configuration, accidental sharing
This is the environment where most developers first encounter OpenClaw. You’re experimenting, learning, iterating quickly. The primary risks are self-inflicted: storing credentials in git, leaving passwords in shell history, sharing the dev machine with someone who shouldn’t have access. The security posture here should be: “strong enough that I don’t leak credentials if I’m not careful, but flexible enough that I can iterate quickly without friction.” You don’t need mTLS or JWT; you need sensible defaults that protect you from your own mistakes.
Medium Threat Model (Team Server):
- Multiple developers have SSH access
- Some non-critical services run on the box (CI/CD, monitoring, logs)
- Network is corporate LAN (behind firewall, but shared infrastructure)
- Risk: Accidental privilege escalation, malicious insider, network compromise, service-to-service attacks
This is where most teams hit the wall. You’re past personal development. Multiple people need access. The box is shared, but it’s still somewhat trusted (it’s on corporate infrastructure). The risks escalate: if one service is compromised, can it reach OpenClaw? If a dev’s SSH key is stolen, what can they do? If someone makes a mistake with file permissions, what gets exposed? This is where you start needing real access control, not just “local = secure.”
High Threat Model (Production Box):
- Multiple services compete for resources
- Untrusted code may run (containers, deployed functions, third-party integrations)
- Network is public or semi-public (internet-facing, cloud infrastructure)
- Risk: Container escape, kernel vulnerability, supply-chain attack, sophisticated attackers, compliance requirements
This is the environment where you’re operating critical infrastructure. The assumption is that something else on the box will be compromised at some point. Your job is to make sure that compromise doesn’t automatically spread to OpenClaw. This requires defense-in-depth, comprehensive logging, incident response capabilities, and compliance auditing. You’re not trying to prevent all attacks; you’re trying to make attacks expensive and detectable.
Matching your configuration to your threat model:
Applying high-threat-model security to a dev machine is overkill and makes iteration painful. Applying low-threat-model security to production is negligent. The key is matching your configuration to your actual threat context. For each threat model, we have specific configuration profiles.
Best Practice Configurations
Let’s walk through three deployment profiles.
Profile A: Secure Local Development (Minimal Threat Model)
You’re running OpenClaw on your workstation for development. You control physical access and there’s no untrusted code running on the box.
gateway:
host: "127.0.0.1"
port: 18789
auth:
token: "dev-token-change-in-prod"
password: "dev-password-change-in-prod"
token_expiration_hours: 24
require_https: false # Acceptable for loopback; HTTP is fine here
tls:
enabled: false
dashboard:
enabled: true
Rationale: Loopback binding is sufficient. Weak credentials are acceptable because there’s no network exposure. But get these credentials out of the box before moving to production.
Verification:
curl -H "Authorization: Bearer dev-token-change-in-prod" \
https://automateanddeploy.com:18789/api/v1/agents
# Should return agent list
# Unauthenticated request should fail
curl https://automateanddeploy.com:18789/api/v1/agents
# Should return 401 Unauthorized
Profile B: Secure Server Deployment (High Threat Model)
OpenClaw runs on a dedicated server in your infrastructure. Untrusted code might run on the same box. Network isolation isn’t complete.
gateway:
host: "127.0.0.1" # Loopback only
port: 18789
auth:
token: "$(GATEWAY_TOKEN)" # From secrets manager
password: "$(GATEWAY_PASSWORD_BCRYPT)"
token_expiration_hours: 4 # Short-lived tokens
require_https: true
token_rotation_interval_hours: 24
tls:
enabled: true
cert_file: "/etc/openclaw/gateway.crt"
key_file: "/etc/openclaw/gateway.key"
client_auth: "required" # mTLS
client_ca_file: "/etc/openclaw/client-ca.crt"
ratelimit:
enabled: true
requests_per_second: 10
burst: 20
cors:
enabled: false # Disable if not needed
logging:
level: "debug"
redact_tokens: true
dashboard:
enabled: false # Disable dashboard in production
Rationale:
- Loopback binding prevents network access
- TLS encrypts in-transit tokens
- mTLS (mutual TLS) requires client certificates; even if an attacker steals a token, they can’t use it without the cert
- Short token expiration (4 hours) limits the window if a token is leaked
- Token rotation every 24 hours ensures old tokens don’t accumulate
- Rate limiting prevents brute-force attacks
- Redacted logging prevents tokens from appearing in logs
- Dashboard disabled because production shouldn’t have a UI
mTLS Deep Dive: Mutual TLS means both the client and server authenticate. Not just the client trusting the server certificate, but the server verifying the client’s certificate. This means:
# Client needs a certificate signed by the CA
# Server has the CA certificate and verifies it
# Client connects:
curl -H "Authorization: Bearer $TOKEN" \
--cert /path/to/client.crt \
--key /path/to/client.key \
--cacert /etc/openclaw/ca.crt \
https://localhost:18789/api/v1/agents
If an attacker steals the token, they can’t use it because they don’t have the client certificate. This is defense in depth.
Credential Rotation Procedure:
# Generate new token
NEW_TOKEN=$(openssl rand -hex 32)
# Store in secrets manager
aws secretsmanager update-secret \
--secret-id openclaw/gateway-token \
--secret-string "$NEW_TOKEN"
# Reload OpenClaw (or use hot-reload if supported)
systemctl restart openclaw
# Verify
curl -H "Authorization: Bearer $NEW_TOKEN" \
--cert /etc/openclaw/client.crt \
--key /etc/openclaw/client.key \
--cacert /etc/openclaw/ca.crt \
https://localhost:18789/api/v1/agents
Profile C: Tailnet-Bound Gateway (Multi-Location Deployment)
OpenClaw needs to be accessed from multiple locations securely. You’re using Tailscale for network isolation.
gateway:
host: "100.100.100.1" # Tailscale IP (your custom derp server or standard tailnet IP)
port: 18789
auth:
token: "$(GATEWAY_TOKEN)"
password: "$(GATEWAY_PASSWORD_BCRYPT)"
token_expiration_hours: 2
require_https: true
token_rotation_interval_hours: 12
tls:
enabled: true
cert_file: "/etc/openclaw/gateway.crt"
key_file: "/etc/openclaw/gateway.key"
# Use Let's Encrypt with DNS validation for tailnet domain
rate_limit:
enabled: true
requests_per_second: 10
logging:
level: "info"
redact_tokens: true
syslog:
enabled: true
facility: "local0"
dashboard:
enabled: true
session_timeout_minutes: 15
require_password_on_every_login: false
Rationale:
- Tailscale network binding means only authenticated Tailnet members can reach the gateway
- Adds an additional layer: network auth (Tailscale) + gateway auth (token)
- Shorter token expiration and rotation because you’re more exposed to the network
- TLS with proper certificates for the tailnet domain
- All access is logged to syslog for centralized monitoring
- Dashboard enabled because Tailnet members are semi-trusted
- Session timeouts prevent unattended sessions from being hijacked
Setup:
# Install Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
# Authenticate to Tailnet
sudo tailscale up --auth-once
# Assign a static Tailnet IP or use the auto-assigned one
tailscale ip -4
# Configure OpenClaw to listen on that IP
# (Use the Tailscale IP from above, e.g., 100.x.x.x)
# Now, team members on your Tailnet can access:
# https://openclaw.your-tailnet.ts.net:18789/dashboard
# (Make sure DNS is configured for the Tailnet domain)
This approach gives you the best of both worlds: network isolation (Tailscale) and application-level authentication (tokens). Even if someone breaks into the Tailnet, they still need to authenticate to OpenClaw.
The Token Storage Problem
Here’s a hidden gotcha: where do you store the token? This is where most deployments fail.
Wrong Way 1: In the config file (committed to git)
gateway:
auth:
token: "super-secret-token-12345"
If you commit this, it’s in git history forever. Revoking it requires rotating all tokens and restarting all clients. And if the git repo is pushed to GitHub, it’s public. GitHub will scan it and warn you, but the damage is done—the token has been in public for minutes or hours.
Wrong Way 2: In environment variables (visible in ps)
export GATEWAY_TOKEN="super-secret-token-12345"
openclaw start
Any process on the box can read /proc/[pid]/environ and extract it. No special privileges required.
# Attacker does this:
cat /proc/12345/environ | grep GATEWAY_TOKEN
# Attacker has it.
Wrong Way 3: In shell history
# User runs:
export GATEWAY_TOKEN="super-secret-token-12345"
# Attacker reads shell history:
cat ~/.bash_history | grep GATEWAY_TOKEN
# Token is compromised.
Right Way 1: Secrets manager with restricted IAM
# Fetch from secrets manager at startup (one-time)
GATEWAY_TOKEN=$(aws secretsmanager get-secret-value \
--secret-id openclaw/gateway-token \
--query SecretString \
--output text)
# Pass to OpenClaw via stdin or a temporary file with mode 0600
echo "$GATEWAY_TOKEN" | openclaw start --token-stdin
# Clear the variable immediately
unset GATEWAY_TOKEN
This way, the token is fetched from the secrets manager at runtime, passed to OpenClaw via stdin, and never stored on disk or in environment variables.
Right Way 2: Locked-down config file with restricted permissions
# Create config with 0600 permissions (readable only by the openclaw user)
echo "token: $(openssl rand -hex 32)" > /opt/openclaw/config.yaml
chmod 600 /opt/openclaw/config.yaml
chown openclaw:openclaw /opt/openclaw/config.yaml
# Verify only the openclaw user can read it
ls -la /opt/openclaw/config.yaml
# Should show: -rw------- 1 openclaw openclaw ...
# Even root can't read it without su'ing to the openclaw user
# (Well, technically root can read anything, but this makes it explicit)
Right Way 3: OS-level secret storage (macOS Keychain, Linux Secret Service)
On macOS, use Keychain:
# Store token in Keychain
security add-generic-password -a openclaw -s gateway-token -w "your-token-here"
# Retrieve token
security find-generic-password -a openclaw -s gateway-token -w
On Linux with systemd user units:
# Use systemd credential storage
systemctl set-environment GATEWAY_TOKEN=$(openssl rand -hex 32)
# OpenClaw reads it from the systemd environment
The principle is: secrets should not live on the filesystem as plaintext. They should live in a secrets manager, a secure enclave, or OS-level credential storage.
Monitoring and Alert Rules
Set up alerts for authentication anomalies:
alerts:
- name: "Failed gateway auth attempts"
condition: "gateway_auth_failures > 5 in 5m"
severity: "high"
action: "page_oncall"
- name: "Gateway token rotation overdue"
condition: "token_last_rotated_hours > 24"
severity: "medium"
action: "notify_slack"
- name: "Unusual gateway API activity"
condition: "requests_from_ip != expected_cidrs"
severity: "high"
action: "page_oncall"
- name: "TLS certificate expiration warning"
condition: "tls_cert_expiry_days < 30"
severity: "medium"
action: "notify_slack"
- name: "Token stolen or reused from unexpected location"
condition: "same_token_from_different_ip"
severity: "critical"
action: "page_oncall_immediately"
- name: "Dashboard password failures"
condition: "dashboard_auth_failures > 10 in 5m"
severity: "medium"
action: "temporarily_lock_dashboard"
In your log aggregation system (ELK, Splunk, etc.):
# Query: All failed authentication attempts
gateway_auth_failures
| stats count by source_ip, timestamp
| where count > 3 in 5min
# Query: Token usage patterns (detect stolen tokens)
gateway_api_requests
| stats count by token_hash, source_ip
| where source_ip changes unexpectedly
# Query: Dashboard access (detect unauthorized UI access)
gateway_dashboard_access
| where auth_method == "password"
| stats count by session_id, user_agent
# Query: TLS handshake failures (detect certificate issues)
gateway_tls_handshake_failures
| stats count by error_reason
| where count > 0
The last one is important: if TLS handshakes are failing, it might be a legitimate misconfiguration, or it might be someone trying to connect without the proper client certificate.
The Incident Response Playbook
If you suspect gateway authentication is compromised:
1. Immediately rotate the token and password:
NEW_TOKEN=$(openssl rand -hex 32)
aws secretsmanager update-secret \
--secret-id openclaw/gateway-token \
--secret-string "$NEW_TOKEN"
systemctl restart openclaw
Do this within seconds. If you wait minutes, the attacker has more time to use the stolen token.
2. Check the logs for unauthorized API calls:
grep "gateway_api" /var/log/openclaw/*.log | \
grep -v "expected_token_hash" | \
head -20
Look for API calls that shouldn’t have happened. Invoked skills, agents spawned, configurations modified.
3. Review agent activity during the compromise window:
# Which skills were invoked?
grep "skill_invocation" /var/log/openclaw/*.log | \
jq '.timestamp, .skill_name, .agent_id' | \
sort -u
This tells you what damage was done. If a “delete-all-data” skill was invoked, you know to look for data loss.
4. Rotate all credentials the agents touched:
Database passwords, API keys, SSH credentials—everything that agent had access to. If an agent can access your database, and the gateway is compromised, the database is compromised.
5. Deploy a security update to prevent re-compromise:
Fix the vulnerability that allowed the breach (patch a vulnerable dependency, close an open port, enable a firewall rule, etc.). Don’t just rotate credentials and assume you’re safe. Find the root cause and fix it.
6. Notify stakeholders:
If sensitive data was accessed or modified, you may have legal obligations to notify users or customers. Do this immediately.
The Philosophy
Gateway authentication is defense-in-depth. Loopback binding prevents network access. Tokens prevent unauthorized API calls. mTLS prevents token replay. Short expiration and rotation limit the blast radius of compromise.
But here’s the uncomfortable truth: if an attacker has shell access, they will eventually find a way to interact with the gateway. Token storage, process inspection, session hijacking—there are multiple vectors.
The goal isn’t to make it impossible (it’s not). The goal is to make it difficult and detectable. Every additional layer adds delay and creates an audit trail. By the time they’ve stolen a token, rotated it, used it to invoke a skill, and exfiltrated data, you’ve (hopefully) detected it via logging and rate limiting.
That’s why comprehensive logging and alerts are non-negotiable. Gateway authentication is only as strong as your monitoring.
Token Generation Best Practices
Here’s a concrete example of generating, storing, and rotating tokens properly.
Initial token generation:
# Generate a cryptographically strong token
TOKEN=$(openssl rand -hex 32)
echo "$TOKEN"
# Output: a7f3e8c4b2d9e1f6a4c7b5d9e2f4c8a1b3d6e9f2c5a8b1d4e7f9c2a5b8d1
# Store in AWS Secrets Manager
aws secretsmanager create-secret \
--name openclaw/gateway-token \
--secret-string "$TOKEN"
# Or in Vault
vault kv put secret/openclaw/gateway token="$TOKEN"
# Clear the variable immediately
unset TOKEN
Rotation workflow (monthly):
#!/bin/bash
# monthly-token-rotation.sh
# Generate new token
NEW_TOKEN=$(openssl rand -hex 32)
# Update secret
aws secretsmanager update-secret \
--secret-id openclaw/gateway-token \
--secret-string "$NEW_TOKEN"
# Reload OpenClaw (gracefully)
systemctl reload openclaw
# Wait for connections to drain (30 seconds)
sleep 30
# Hard restart if needed
systemctl restart openclaw
# Verify
curl -H "Authorization: Bearer $NEW_TOKEN" \
https://localhost:18789/api/v1/agents
echo "Token rotated successfully"
Token expiration handling:
If you set token_expiration_hours: 4, old tokens stop working after 4 hours. This forces clients to re-authenticate:
# Client-side handling
TOKEN=$(curl -s https://auth-service/token \
-H "Authorization: Bearer $OLD_TOKEN")
# Use new TOKEN
curl -H "Authorization: Bearer $TOKEN" \
https://localhost:18789/api/v1/agents
Dashboard Security Deep Dive
The dashboard is a web UI. It’s vulnerable to different attacks than the API.
CSRF (Cross-Site Request Forgery):
An attacker tricks you into visiting their website, which makes requests to the dashboard without you knowing. Mitigation:
gateway:
dashboard:
csrf_protection: enabled
csrf_token_length: 32
same_site_cookie: "strict" # Only send cookie with same-site requests
XSS (Cross-Site Scripting):
An attacker injects malicious JavaScript into the dashboard. Mitigation:
gateway:
dashboard:
csp_headers: true # Content Security Policy
x_frame_options: "DENY" # Prevent clickjacking
x_content_type_options: "nosniff"
Session hijacking:
An attacker steals your session cookie. Mitigation:
gateway:
dashboard:
secure_cookies: true # HTTPS only
httponly_cookies: true # Not accessible via JavaScript
session_timeout_minutes: 15
regenerate_session_on_login: true
Example full dashboard security config:
gateway:
dashboard:
enabled: true
auth_method: "password" # Or "oauth" if integrated with SSO
# Session management
session:
timeout_minutes: 15
regenerate_on_login: true
secure: true # HTTPS only
httponly: true # Prevent XSS access
samesite: "strict" # CSRF protection
# Content security
headers:
content_security_policy: "default-src 'self'"
x_frame_options: "DENY"
x_content_type_options: "nosniff"
x_xss_protection: "1; mode=block"
referrer_policy: "strict-origin-when-cross-origin"
# UI behavior
ui:
logout_on_inactivity: true
confirm_dangerous_actions: true
mask_sensitive_data: true
audit_all_actions: true
Browser-Pivot Attack Mitigation Strategies
We talked about the attack. Here are concrete mitigations beyond loopback binding.
Strategy 1: Disable the dashboard entirely
gateway:
dashboard:
enabled: false # API-only mode
If you only use the API (via CLI or integration), disable the web dashboard. One fewer attack surface.
Strategy 2: OS-level access control
Only the openclaw user can read the gateway config:
# Gateway config file
-rw------- 1 openclaw openclaw /etc/openclaw/gateway.yaml
# Only openclaw user can read credentials
Even if an attacker gets shell access as a different user, they can’t read the config.
Strategy 3: Separate credentials for API vs Dashboard
Use different tokens for API and different passwords for dashboard. If one is compromised, the other stays safe:
gateway:
auth:
api:
token: "api-token-separate"
token_expiration_hours: 4
dashboard:
password: "dashboard-password-separate"
session_timeout_minutes: 15
Now an attacker who steals the dashboard password can’t use the API. They’re limited to the dashboard.
Strategy 4: IP-based dashboard restriction
gateway:
dashboard:
allowed_ips:
- "127.0.0.1" # Localhost only
- "192.168.1.100" # Specific trusted machine
If someone gains shell access from a different IP, they can’t reach the dashboard.
Token Revocation and Blocklist Management
What happens when you suspect a token is compromised, but you can’t wait for its expiration?
Immediate revocation:
# Blocklist the token (if your system supports it)
# OR just restart OpenClaw immediately
systemctl restart openclaw
# Generate a new token
NEW_TOKEN=$(openssl rand -hex 32)
aws secretsmanager update-secret \
--secret-id openclaw/gateway-token \
--secret-string "$NEW_TOKEN"
# Notify all clients to update their credentials
curl -X POST https://notify-service/broadcast \
-d '{"message": "Gateway token rotated. Update your config."}'
Persistent blocklist (for longer-term tracking):
# In OpenClaw config
gateway:
auth:
token_blocklist:
- "old-compromised-token-1"
- "old-compromised-token-2"
blocklist_check: true # Always check before accepting token
Any token in the blocklist is immediately rejected, even if it’s not expired.
Multi-Factor Authentication for Dashboard
If you’re really paranoid (good!), add MFA to the dashboard:
gateway:
dashboard:
auth_method: "password_with_mfa"
mfa:
provider: "totp" # Time-based OTP (Google Authenticator, etc.)
backup_codes: 10
require_for_dangerous_actions: true
Now even if an attacker steals your password, they need your TOTP device to log in.
Forensics and Post-Incident Analysis
After a security incident, you need to understand what happened.
Log preservation:
# Copy logs to external storage before rotating
cp /var/log/openclaw/*.log /backup/openclaw-logs/$(date +%Y%m%d)/
# Compress and archive
tar czf /backup/openclaw-logs-$(date +%Y%m%d).tar.gz /backup/openclaw-logs/
Key questions to answer:
# 1. When was the token compromised?
grep "auth_failure" /var/log/openclaw/*.log | tail -20
# 2. What API endpoints were called?
grep "api_request" /var/log/openclaw/*.log | jq '.endpoint' | sort | uniq -c
# 3. Which agents were invoked?
grep "skill_invocation" /var/log/openclaw/*.log | jq '.skill_name, .timestamp'
# 4. What data was accessed?
grep "data_access" /var/log/openclaw/*.log | jq '.resource, .action'
# 5. Any data exfiltration?
grep -E "large_response|data_download" /var/log/openclaw/*.log
Real-World Deployment Walkthrough
Let’s tie this together with a concrete deployment scenario: a production OpenClaw server serving multiple teams.
Requirements:
- API access from internal tools and scripts
- Dashboard access for operators (with audit logging)
- Monitoring and alerting
- Regular credential rotation
- Compliance with security policies
Step 1: Set up secrets management
# Using AWS Secrets Manager
AWS_REGION=us-east-1
# Create secrets
aws secretsmanager create-secret \
--name openclaw/prod/gateway-token \
--secret-string "$(openssl rand -hex 32)" \
--region $AWS_REGION
aws secretsmanager create-secret \
--name openclaw/prod/gateway-password \
--secret-string "$(openssl rand -base64 32)" \
--region $AWS_REGION
# Optionally add a description for audit purposes
aws secretsmanager update-secret \
--secret-id openclaw/prod/gateway-token \
--description "API token for production OpenClaw gateway" \
--add-replica-regions RegionList='[{RegionName=us-west-2}]'
Step 2: Deploy with secure credential injection
#!/bin/bash
# deploy-openclaw.sh
set -e
# Fetch secrets at deployment time
GATEWAY_TOKEN=$(aws secretsmanager get-secret-value \
--secret-id openclaw/prod/gateway-token \
--query SecretString \
--output text)
GATEWAY_PASSWORD=$(aws secretsmanager get-secret-value \
--secret-id openclaw/prod/gateway-password \
--query SecretString \
--output text)
# Create temporary config file (mode 0600)
CONFIG_FILE=$(mktemp)
chmod 600 "$CONFIG_FILE"
cat > "$CONFIG_FILE" << EOF
gateway:
host: "127.0.0.1"
port: 18789
auth:
token: "$GATEWAY_TOKEN"
password: "$GATEWAY_PASSWORD"
token_expiration_hours: 4
require_https: true
tls:
enabled: true
cert_file: /etc/openclaw/gateway.crt
key_file: /etc/openclaw/gateway.key
ratelimit:
enabled: true
requests_per_second: 20
logging:
level: debug
redact_tokens: true
EOF
# Start OpenClaw with config
systemctl stop openclaw || true
cp "$CONFIG_FILE" /etc/openclaw/gateway.conf
chown openclaw:openclaw /etc/openclaw/gateway.conf
chmod 600 /etc/openclaw/gateway.conf
systemctl start openclaw
# Clean up
rm -f "$CONFIG_FILE"
unset GATEWAY_TOKEN GATEWAY_PASSWORD
echo "Deployment complete"
Step 3: Set up monitoring
# prometheus-alerts.yaml
groups:
- name: openclaw_gateway
rules:
- alert: GatewayAuthFailures
expr: rate(gateway_auth_failures_total[5m]) > 10
for: 5m
annotations:
summary: "High authentication failure rate on gateway"
runbook: "Check if credentials are correct, token rotated, or if there's an attack"
- alert: TokenRotationOverdue
expr: (time() - gateway_token_last_rotation_seconds) > 86400
annotations:
summary: "Gateway token hasn't been rotated in >24 hours"
runbook: "Rotate token immediately using token-rotation script"
- alert: UnauthorizedIPAccess
expr: gateway_api_requests_from_unexpected_source > 0
annotations:
summary: "API requests from unexpected IP address"
runbook: "Investigate source IP, may indicate compromised credential"
- alert: TLSCertExpiringSoon
expr: (tls_cert_not_after_seconds - time()) < 2592000
annotations:
summary: "TLS certificate expires within 30 days"
runbook: "Renew certificate and redeploy"
Step 4: Automate token rotation
#!/bin/bash
# token-rotation-cronjob.sh
# Run daily via cron: 0 2 * * * /opt/openclaw/token-rotation-cronjob.sh
set -e
# Log to syslog
exec 1> >(logger -s -t openclaw-token-rotation)
exec 2>&1
echo "Starting token rotation..."
# Generate new token
NEW_TOKEN=$(openssl rand -hex 32)
# Store in secrets manager
aws secretsmanager update-secret \
--secret-id openclaw/prod/gateway-token \
--secret-string "$NEW_TOKEN" \
--region us-east-1
# Signal OpenClaw to reload
systemctl reload openclaw
# Wait for reload to complete
sleep 10
# Test new token
HEALTH=$(curl -s -H "Authorization: Bearer $NEW_TOKEN" \
https://localhost:18789/api/v1/health || echo "failed")
if [[ "$HEALTH" == *"ok"* ]]; then
echo "Token rotation successful"
# Send notification to Slack
curl -X POST "$SLACK_WEBHOOK" \
-d '{"text": "OpenClaw gateway token rotated successfully"}'
else
echo "Token rotation FAILED - reverting"
# Revert to previous token (stored separately)
systemctl restart openclaw
exit 1
fi
Step 5: Audit access logs
#!/bin/bash
# audit-gateway-access.sh
# Run weekly
echo "=== Gateway API Access Summary ==="
grep "gateway_api_request" /var/log/openclaw/*.log | \
jq -r '.timestamp, .source_ip, .endpoint, .method, .auth_method, .status' | \
column -t
echo ""
echo "=== Authentication Failures ==="
grep "auth_failure" /var/log/openclaw/*.log | \
jq -r '.timestamp, .source_ip, .reason' | \
column -t
echo ""
echo "=== Suspicious Activity ==="
grep -E "rate_limit|token_rejected|ip_blocklist" /var/log/openclaw/*.log | \
jq -r '.timestamp, .event_type, .details' | \
column -t
API Client Configuration Examples
Different clients have different ways to handle authentication. Here’s how to configure them properly.
cURL (command line):
# Store token in environment (insecure if in .bashrc!)
export OPENCLAW_TOKEN=$(aws secretsmanager get-secret-value \
--secret-id openclaw/prod/gateway-token \
--query SecretString --output text)
# Use token
curl -H "Authorization: Bearer $OPENCLAW_TOKEN" \
--cacert /etc/openclaw/ca.crt \
https://localhost:18789/api/v1/agents
# Better: fetch token each time
curl -H "Authorization: Bearer $(aws secretsmanager get-secret-value --secret-id openclaw/prod/gateway-token --query SecretString --output text)" \
--cacert /etc/openclaw/ca.crt \
https://localhost:18789/api/v1/agents
Python client:
# Fetch token from secrets manager
secrets_client = boto3.client('secretsmanager')
token = secrets_client.get_secret_value(
SecretId='openclaw/prod/gateway-token'
)['SecretString']
# Make authenticated request
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(
'https://localhost:18789/api/v1/agents',
headers=headers,
verify='/etc/openclaw/ca.crt'
)
print(response.json())
Go client:
package main
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
"net/http"
)
func main() {
// Load AWS config
cfg, _ := config.LoadDefaultConfig(context.TODO())
client := secretsmanager.NewFromConfig(cfg)
// Fetch token
result, _ := client.GetSecretValue(context.TODO(), &secretsmanager.GetSecretValueInput{
SecretId: "openclaw/prod/gateway-token",
})
token := *result.SecretString
// Make authenticated request
req, _ := http.NewRequest("GET", "https://localhost:18789/api/v1/agents", nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
httpClient := &http.Client{}
resp, _ := httpClient.Do(req)
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
}
Preventing Common Misconfiguration Mistakes
Most security breaches aren’t due to advanced attacks—they’re due to misconfiguration. Let’s walk through the most common mistakes and how to prevent them.
Mistake 1: Committing credentials to git
You commit a config file with the token. It’s in git history forever.
Prevention:
# Use .gitignore
echo "config.yaml" >> .gitignore
echo ".env" >> .gitignore
# Or use git-secrets to scan commits
brew install git-secrets
git secrets --install
git secrets --register-aws
# Only commit config templates
cp config.yaml config.yaml.template
# Edit template to remove secrets
git add config.yaml.template
Mistake 2: Weak token strength
Using short random strings (12 characters) instead of proper cryptographic tokens (32+ bytes).
Prevention:
# Always generate with cryptographic randomness
openssl rand -hex 32 # 64 hex chars = 256 bits. GOOD.
openssl rand -base64 32 # 44 chars. GOOD.
# Bad examples to avoid:
# "MySecret123" - too short
# "token123456789" - predictable
# UUIDs - not enough entropy
Mistake 3: Token in logs
Logging the full token in error messages or debug output.
Prevention:
# In OpenClaw config, enable token redaction
logging:
redact_tokens: true # Masks tokens in logs
redact_patterns:
- "Bearer [a-f0-9]{64}"
- "token: [a-f0-9]{64}"
# When writing logs manually:
echo "Authorization: Bearer ****${TOKEN:(-8)}" # Only show last 8 chars
Mistake 4: No HTTPS in production
Sending credentials over HTTP (even on loopback, if accessed remotely).
Prevention:
gateway:
auth:
require_https: true # Enforce HTTPS
tls:
enabled: true
cert_file: /etc/openclaw/gateway.crt
key_file: /etc/openclaw/gateway.key
# HTTP requests get rejected
If you try to connect with HTTP:
curl https://automateanddeploy.com:18789/api/v1/agents
# Response: 403 Forbidden - HTTPS required
Mistake 5: Same token for API and dashboard
If one secret is compromised, both API and UI are compromised.
Prevention:
gateway:
auth:
api_token: "token-for-api-only"
dashboard_password: "password-for-ui-only"
# Or separate them entirely:
api:
auth:
token: "api-token"
dashboard:
auth:
password: "dashboard-password"
Now if the dashboard password leaks, the API is still secure.
Mistake 6: No token rotation schedule
Tokens that live forever become permanent attack vectors.
Prevention:
# Set up a rotation schedule
# Option 1: Cron job (automatic)
0 2 * * * /opt/openclaw/rotate-token.sh
# Option 2: Manual but tracked
# Keep a calendar of rotation dates
# Option 3: Policy-enforced
# Make token_expiration_hours non-configurable (hard-coded to 4 or 24)
Mistake 7: Overly permissive rate limiting
Allowing brute-force attacks by having weak rate limits.
Prevention:
gateway:
ratelimit:
enabled: true
requests_per_second: 10 # Aggressive limit
burst: 5 # Prevent burst attacks
by_ip: true # Rate limit per source IP
by_token: true # Rate limit per token
# Lock account after N failures
auth_failures:
threshold: 5
lockout_duration_minutes: 15
Now an attacker can only try 5 tokens every 15 minutes. Brute-forcing 10,000 tokens takes 30,000 minutes (21 days) without hitting a lockout.
Security Checklist: Before Going to Production
Before you deploy your gateway to production, go through this checklist:
## Pre-Production Security Checklist
### Credentials Management
- [ ] Token generated with cryptographic randomness (32+ bytes)
- [ ] Token stored in secrets manager, not in config files
- [ ] Token rotation script is working and tested
- [ ] Password hashed with bcrypt (not plaintext)
- [ ] No credentials in git history
- [ ] No credentials in environment variables
- [ ] Secrets manager has audit logging enabled
### Network & TLS
- [ ] Gateway binds to 127.0.0.1 (loopback only)
- [ ] TLS enabled with proper certificates
- [ ] Certificates are valid and not expired
- [ ] Client CA certificate for mTLS is in place
- [ ] HTTPS is required (no HTTP fallback)
- [ ] Firewall rules restrict access to gateway port
### Access Control
- [ ] Dashboard disabled if not needed
- [ ] Separate auth for API vs dashboard
- [ ] Rate limiting enabled
- [ ] Token blocklist implemented
- [ ] Session timeout is short (15 minutes or less)
- [ ] CSRF protection enabled for dashboard
### Logging & Monitoring
- [ ] Token redaction enabled in logs
- [ ] All auth failures logged
- [ ] All successful logins logged
- [ ] Alerts configured for auth anomalies
- [ ] Log aggregation is working
- [ ] Alerts are being delivered to on-call
### Testing
- [ ] Unauthenticated requests are rejected (401)
- [ ] Weak credentials are rejected
- [ ] Rate limits are enforced
- [ ] Token expiration works correctly
- [ ] TLS errors are handled gracefully
- [ ] Credential rotation doesn't cause downtime
### Documentation
- [ ] Token rotation procedure documented
- [ ] Emergency revocation procedure documented
- [ ] Incident response playbook created
- [ ] Run-books for common issues written
Print this, go through it methodically, and mark off each item before deploying to production.
Advanced: JWT Tokens Instead of Opaque Bearer Tokens
We’ve been talking about opaque bearer tokens (random 64-character strings). Some teams prefer JWT (JSON Web Tokens) which are self-contained and signed.
Why JWT?
- Self-contained (no server-side lookup needed)
- Can include claims (user ID, permissions, expiration)
- Cryptographically signed (can’t be forged)
- Good for distributed systems
Why not JWT?
- Token payload is Base64-encoded (not encrypted) – anyone can read the claims
- Can’t revoke a token immediately (it’s valid until expiration)
- Slightly more complex to generate and validate
JWT configuration:
gateway:
auth:
token_type: jwt
jwt:
algorithm: HS256 # HMAC with SHA256
secret: "your-jwt-signing-secret"
expiration_seconds: 3600 # 1 hour
claims:
iss: "openclaw" # Issuer
sub: "api-client" # Subject
aud: "openclaw-gateway" # Audience
JWT payload example:
{
"iss": "openclaw",
"sub": "api-client",
"aud": "openclaw-gateway",
"exp": 1234567890,
"iat": 1234567000,
"permissions": ["read:agents", "invoke:skills"]
}
An attacker can read these claims (it’s just Base64), but can’t modify them without the signing secret.
Client-side JWT handling:
# Generate JWT
secret = "your-jwt-signing-secret"
payload = {
"iss": "openclaw",
"sub": "api-client",
"aud": "openclaw-gateway",
"exp": int(time.time()) + 3600,
"iat": int(time.time()),
}
token = jwt.encode(payload, secret, algorithm="HS256")
# Use token
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(
"https://localhost:18789/api/v1/agents",
headers=headers
)
Important: JWT tokens can’t be revoked before expiration. If a token is stolen, it’s valid until expiration. This is why JWT is better for short-lived tokens (1-4 hours) and less ideal for long-lived ones.
For production OpenClaw, we recommend opaque bearer tokens with short expiration (4 hours) and regular rotation (every 24 hours). JWT is better for specific use cases like service-to-service communication.
Testing Your Gateway Security
Before relying on your gateway security, test it thoroughly.
Unit tests for auth logic:
# test_gateway_auth.py
from openclaw.gateway import auth
def test_valid_token_accepted():
"""Valid token should be accepted"""
token = auth.generate_token()
assert auth.validate_token(token) == True
def test_invalid_token_rejected():
"""Invalid token should be rejected"""
assert auth.validate_token("invalid-token") == False
def test_expired_token_rejected():
"""Expired token should be rejected"""
token = auth.generate_token(expiration_seconds=-1)
assert auth.validate_token(token) == False
def test_token_rotation_works():
"""Token rotation should invalidate old token"""
old_token = auth.get_current_token()
auth.rotate_token()
assert auth.validate_token(old_token) == False
def test_rate_limiting_enforced():
"""Rate limit should reject excessive requests"""
limiter = auth.RateLimiter(requests_per_second=1)
limiter.check_rate() # First request
with pytest.raises(auth.RateLimitExceeded):
limiter.check_rate() # Second request immediately after
Integration tests against running gateway:
#!/bin/bash
# test-gateway-integration.sh
GATEWAY_URL="https://localhost:18789"
TOKEN=$(aws secretsmanager get-secret-value --secret-id openclaw/gateway-token --query SecretString --output text)
CA_CERT="/etc/openclaw/ca.crt"
echo "Testing gateway security..."
# Test 1: Valid token accepted
echo -n "Test 1 (valid token): "
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
--cacert $CA_CERT \
$GATEWAY_URL/api/v1/agents)
if [ "$STATUS" = "200" ]; then echo "PASS"; else echo "FAIL ($STATUS)"; fi
# Test 2: Invalid token rejected
echo -n "Test 2 (invalid token): "
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer invalid-token" \
--cacert $CA_CERT \
$GATEWAY_URL/api/v1/agents)
if [ "$STATUS" = "401" ]; then echo "PASS"; else echo "FAIL ($STATUS)"; fi
# Test 3: No token rejected
echo -n "Test 3 (no token): "
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
--cacert $CA_CERT \
$GATEWAY_URL/api/v1/agents)
if [ "$STATUS" = "401" ]; then echo "PASS"; else echo "FAIL ($STATUS)"; fi
# Test 4: HTTP (unencrypted) rejected
echo -n "Test 4 (HTTP not allowed): "
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
https://automateanddeploy.com:18789/api/v1/agents 2>/dev/null || echo "connection-refused")
if [ "$STATUS" = "connection-refused" ] || [ "$STATUS" = "400" ]; then echo "PASS"; else echo "FAIL"; fi
# Test 5: Rate limiting works
echo -n "Test 5 (rate limiting): "
for i in {1..20}; do
curl -s -H "Authorization: Bearer $TOKEN" \
--cacert $CA_CERT \
$GATEWAY_URL/api/v1/agents > /dev/null &
done
wait
echo "PASS (sent 20 requests, check logs for rate limit)"
Run these tests regularly, especially after configuration changes.
Understanding the Browser-Pivot Attack in Detail
We mentioned the browser-pivot attack earlier, but it deserves deeper explanation because it’s the attack most people miss.
The scenario:
An attacker has gained shell access to your server (not through the gateway—through some other vulnerability). They’re a limited user, no special privileges. But they want to compromise OpenClaw.
Step-by-step:
- Attacker opens a browser on the compromised server
- Navigates to https://automateanddeploy.com:18789
- Gateway responds (loopback allows it)
- Dashboard loads and prompts for authentication
At this point, there are multiple attack vectors:
Vector A: Brute-force the dashboard password
# Attacker writes a script to try common passwords
for password in admin password123 openclaw secret; do
curl -X POST https://automateanddeploy.com:18789/login \
-d "username=admin&password=$password"
done
Mitigation: Strong password, rate limiting, account lockout.
Vector B: Extract token from disk
# If config file is readable
cat /opt/openclaw/config.yaml | grep token
# Or from process environment
cat /proc/$(pgrep openclaw)/environ | grep TOKEN
Mitigation: Config file mode 0600, don’t put tokens in environment.
Vector C: Steal session cookie from browser storage
# If OpenClaw is running locally, attacker can:
# 1. Open browser DevTools (Cmd+Option+I)
# 2. Go to Application → Cookies → localhost:18789
# 3. Copy the session cookie
# 4. Use it from command line:
curl -H "Cookie: session=<stolen-cookie>" \
https://automateanddeploy.com:18789/api/v1/agents
Mitigation: Secure cookies (HTTPS only), HTTPOnly flag (prevents JavaScript access), SameSite=Strict.
Vector D: Perform CSRF attacks
If the attacker can trick OpenClaw into making requests:
<!-- Attacker's page, if the user visits it while logged in -->
<img src="https://automateanddeploy.com:18789/api/v1/agents/invoke?agent=delete-all-data" />
The request happens in the user’s context with their session.
Mitigation: CSRF tokens, SameSite cookies.
Why loopback binding prevents remote attacks but not local attacks:
- Remote attacker: Can’t reach loopback at all. Protected.
- Local attacker (shell access): Can reach loopback. Not protected.
This is the key insight. Network isolation is one layer, but not sufficient if the attacker already has shell access.
Full defense against browser-pivot:
gateway:
host: "127.0.0.1" # Loopback (prevents remote attacks)
dashboard:
enabled: false # If not needed, disable entirely
# If you do enable it:
auth:
password: "strong-random-32-char-password"
require_password: true
# Session security
session:
timeout_minutes: 5 # Very short
secure: true # HTTPS only
httponly: true # Not accessible via JavaScript
samesite: "strict" # CSRF protection
# Additional protections
require_mfa: true # TOTP two-factor
lock_after_failures: 3
lockout_duration_minutes: 15
# API layer
auth:
token: "cryptographically-random-token"
require_https: true
# Prevent token theft from storage
token_storage: "memory" # Not on disk
# If token stolen and used:
ratelimit:
enabled: true
requests_per_second: 5 # Aggressive
With these mitigations, even if an attacker has shell access:
- Dashboard is disabled → Can’t use web UI
- If API accessed, token is short-lived (4 hours) and rate-limited (5 req/s)
- Suspicious activity triggers alerts
- Log analysis shows exactly what happened
This is defense-in-depth: multiple layers so that no single compromise is catastrophic.
Threat Intelligence: Staying Ahead of Attacks
The threat landscape changes constantly. How do you stay informed about new attack patterns?
Subscribe to security bulletins:
- CISA alerts (cisa.gov)
- NVD (National Vulnerability Database)
- API security mailing lists
- Your cloud provider’s security bulletins (AWS, Azure, GCP)
Monitor your logs for patterns:
# Weekly log review script
#!/bin/bash
WEEK_AGO=$(date -d "7 days ago" +%Y-%m-%d)
echo "=== Authentication anomalies this week ==="
grep "auth_failure\|token_rejected\|rate_limit_exceeded" /var/log/openclaw/*.log | \
grep -a "$WEEK_AGO" | \
awk -F: '{print $1}' | sort | uniq -c | sort -rn
echo ""
echo "=== IP addresses with multiple failures ==="
grep "auth_failure" /var/log/openclaw/*.log | \
grep -a "$WEEK_AGO" | \
jq '.source_ip' | sort | uniq -c | sort -rn | head -10
echo ""
echo "=== Unusual API activity ==="
grep "api_request" /var/log/openclaw/*.log | \
grep -a "$WEEK_AGO" | \
jq '.endpoint, .method' | sort | uniq -c | sort -rn
Run this weekly and look for patterns that don’t match your normal usage.
Incident response readiness:
Have a playbook ready before an incident happens. It should include:
- Who to notify immediately (security team, on-call, manager)
- What actions to take in first 5 minutes (rotate token, block IPs, snapshot)
- What logs to preserve
- How to communicate with customers/team
- Post-incident review process
Practice this playbook quarterly with a mock incident drill.
Stay patched:
# Check for security updates to OpenClaw
docker pull openclaw:latest
docker inspect openclaw:latest | grep -i security
# Or use Dependabot/Renovate to watch for updates automatically
Final Thought
The gateway is the command center. Locking it down—properly—is non-negotiable. Not just with tokens or passwords, but with the full stack: strong credentials, network isolation, TLS, mTLS, token rotation, rate limiting, and comprehensive logging.
Do it right, and your OpenClaw deployment is a fortress. Do it half-way, and you’re inviting trouble. There’s no in-between.