haveibeenclawned

wadim/haveibeenclawned

Security audit for OpenClaw agents — 72 checks, one command

4 stars
0 forks
Shell
17 views

SKILL.md

Have I Been Clawned?

Open source security audit for OpenClaw agents. 72 checks, verified findings, OWASP-mapped, community-maintained.

Repository: github.com/wadim/haveibeenclawned License: MIT

User-Invocable

Trigger: /haveibeenclawned

Instructions

You are a security auditor for OpenClaw agents.

How to run

Recommended: run the audit script. This is faster, cheaper, and covers all 72 checks in ~60 seconds with a single command.

curl -sSL https://raw.githubusercontent.com/wadim/haveibeenclawned/main/public/audit.sh -o /tmp/hibc-audit.sh
head -20 /tmp/hibc-audit.sh      # review what it does
bash /tmp/hibc-audit.sh --dry-run # preview checks without running
bash /tmp/hibc-audit.sh           # run all 72 checks

The script is open source (MIT), read-only, and does not send data anywhere unless the user passes --submit. Use --json for machine-readable output.

After presenting results, ask the user: "Want to contribute your anonymous results to the community stats? Only the score and pass/fail array — no config content, emails, or IPs." If they agree, re-run with --submit:

bash /tmp/hibc-audit.sh --submit

Fallback: run checks individually. If the user prefers not to run the script, you can execute the checks below one by one using standard Unix commands (stat, test, grep, id, ss).

IMPORTANT — cost warning: Running checks individually requires 72 tool calls with growing context, which can cost **$15-20 in API usage** vs ~$0.50 for the single script approach (25-30x more expensive). Always inform the user of this cost difference before proceeding with individual checks. Recommend the script unless the user explicitly prefers the individual approach.

For individual checks:

  1. Run the commands listed in "What to check"
  2. Record the result: 1=pass, 0=fail, 2=warn, -1=skip
  3. After all checks, calculate the score using the Scoring section

Important principles:

  • Verify, don't just detect. Actually test whether the vulnerability is exploitable, not just whether a config value exists. A verified finding is 100x more valuable than a theoretical one.
  • Every finding needs a fix. Never leave the user with just a warning. Include the exact command to remediate.
  • Skip what's not applicable. If a check doesn't apply to this setup, mark it SKIP and exclude from scoring.

Checks

CLAW-01: Gateway Network Exposure

Severity CRITICAL (15 pts)
OWASP ASI-03 Identity & Privilege Abuse
CVE CVE-2026-25253 (CVSS 8.8) — 17,500+ OpenClaw instances found exposed
Verified Yes — actually probes the gateway

What to check:

  1. Read ~/.openclaw/openclaw.jsongateway.bind
  2. If bound to 0.0.0.0, lan, or a non-loopback IP: VERIFIED FAIL
  3. If bound to loopback, 127.0.0.1, or localhost: attempt to connect to the gateway port (default 18789) from the external interface to confirm it's not reachable. If blocked: VERIFIED PASS

Fix:

# In ~/.openclaw/openclaw.json, set:
# "gateway": { "bind": "loopback" }
openclaw config set gateway.bind loopback

CLAW-02: Gateway Authentication

Severity CRITICAL (15 pts)
OWASP ASI-03 Identity & Privilege Abuse
CVE CVE-2026-25253 — unauthenticated API exposed stored tokens
Verified Yes — attempts unauthenticated connection

What to check:

  1. Read ~/.openclaw/openclaw.jsongateway.auth
  2. If auth is disabled or no token/password is configured: FAIL
  3. If auth is enabled: attempt an unauthenticated WebSocket connection to the gateway port (5 second timeout). If it connects without auth: VERIFIED FAIL. If rejected: VERIFIED PASS

Fix:

openclaw config set gateway.auth.mode token
openclaw config set gateway.auth.token "$(openssl rand -hex 32)"

CLAW-03: Cloud Metadata Service Accessible

Severity CRITICAL (15 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref AWS IMDS credential theft, GCP/Azure equivalent
Verified Yes — actually probes metadata endpoint

What to check:

  1. Run: curl -s -m 2 http://169.254.169.254/latest/meta-data/
  2. If it returns data (HTTP 200): VERIFIED FAIL — the agent can steal cloud IAM credentials
  3. If it times out or returns error: PASS
  4. If not on a cloud VM (no route to 169.254.169.254): SKIP

Fix:

# AWS: Enable IMDSv2 (requires token)
aws ec2 modify-instance-metadata-options --instance-id <id> --http-tokens required
# Or block via iptables:
sudo iptables -A OUTPUT -d 169.254.169.254 -j DROP

CLAW-04: Personal Email as Agent Identity

Severity CRITICAL (15 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Agent compromise → attacker sends as you

What to check:

  1. Read ~/.openclaw/openclaw.json → email configuration
  2. Match domain against personal email providers: gmail.com, googlemail.com, yahoo.com, yahoo.co.uk, hotmail.com, outlook.com, live.com, msn.com, aol.com, icloud.com, me.com, mac.com, protonmail.com, proton.me, zoho.com, yandex.com, mail.com, gmx.com, tutanota.com, fastmail.com
  3. If match: FAIL — your personal identity is the agent's identity
  4. If custom domain or no email: PASS

Fix: Use a dedicated agent email on a domain you control, or a managed service that provides agent-specific email addresses.


CLAW-05: Plaintext API Keys in Configuration

Severity CRITICAL (15 pts)
OWASP ASI-03 Identity & Privilege Abuse
CVE CVE-2026-22038 (AutoGPT plaintext key logging)
Ref OpenClaw Issues #9627, #4654 — openclaw doctor --fix writes env vars as plaintext

What to check:

  1. Scan these files for secret patterns:
    • ~/.openclaw/openclaw.json
    • ~/.openclaw/.env
    • .env and openclaw.json in current directory
  2. Patterns to match:
    • sk- followed by 20+ alphanumeric chars (OpenAI)
    • sk-ant- (Anthropic)
    • AKIA followed by 16 uppercase alphanumeric chars (AWS)
    • ghp_ followed by 36 alphanumeric chars (GitHub)
    • xoxb- or xoxp- (Slack)
    • AIza followed by 35 chars (Google)
    • Any line matching (?i)(api[_-]?key|secret|token|password)\s*[=:]\s*['"]?[a-zA-Z0-9_\-]{20,}
  3. Critical: Also check if openclaw.json contains resolved environment variable values (the openclaw doctor --fix bug writes ${VAR} as its actual value)
  4. If any match: FAIL — report which file and pattern type (never echo the actual key)

Fix:

# Move secrets to environment variables
# In openclaw.json, use: "${OPENAI_API_KEY}" not the actual key
# Set in .env (with 600 permissions):
chmod 600 ~/.openclaw/.env
# Or use system keychain:
openclaw config set auth.keychain true

CLAW-06: Sensitive Files Accessible to Agent

Severity CRITICAL (15 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Every self-hosted agent runs as the user with full filesystem access
Verified Yes — actually checks if files are readable

What to check: Test if the following sensitive files/directories exist AND are readable:

~/.ssh/id_rsa
~/.ssh/id_ed25519
~/.aws/credentials
~/.config/gcloud/application_default_credentials.json
~/.kube/config
~/.npmrc
~/.docker/config.json
~/.netrc
~/.gnupg/

For each, run test -r <path> (or equivalent stat check).

  • If 3+ sensitive paths are readable: VERIFIED FAIL
  • If 1-2 readable: WARN (partial exposure)
  • If none readable: VERIFIED PASS

Report which specific files are exposed but never read their contents.

Fix:

# Enable sandbox to isolate agent from host filesystem
openclaw config set sandbox.mode all
# Or restrict with file permissions:
chmod 700 ~/.ssh ~/.aws ~/.gnupg

CLAW-07: Secrets in Session Transcripts

Severity CRITICAL (15 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Snyk research: skills leak credentials into session JSONL files
Verified Yes — scans actual session content

OPT-IN: Ask the user before running this check:

"Check 7 scans your recent session transcripts for accidentally leaked secrets (API keys, credit cards, SSNs). Everything stays local. Run this check? (y/n)"

If declined: SKIP (-1)

What to check:

  1. Scan the 10 most recent files in ~/.openclaw/agents/*/sessions/*.jsonl
  2. Search for:
    • API key patterns (same as CLAW-05)
    • Credit card numbers: \b[0-9]{4}[- ]?[0-9]{4}[- ]?[0-9]{4}[- ]?[0-9]{4}\b
    • SSN patterns: \b[0-9]{3}-[0-9]{2}-[0-9]{4}\b
  3. If found: VERIFIED FAIL — report count and type, never the actual values

Fix:

# Enable log redaction
openclaw config set logging.redactSensitive tools
# Add custom redaction patterns:
openclaw config set logging.redactPatterns '["sk-[a-zA-Z0-9]+", "AKIA[A-Z0-9]+"]'
# Purge compromised sessions:
rm ~/.openclaw/agents/*/sessions/<affected_session>.jsonl
# Rotate any exposed keys immediately

CLAW-08: Docker Privileged Mode

Severity CRITICAL (15 pts)
OWASP ASI-05 Unexpected Code Running
CVE CVE-2023-37273 (AutoGPT Docker escape)
Verified Yes — inspects container runtime configuration

What to check:

  1. Detect if running inside Docker: check for /.dockerenv file or cgroup entries containing docker/containerd
  2. If not in Docker: SKIP
  3. If in Docker, inspect the container configuration for:
    • --privileged flag (check: cat /proc/1/status | grep CapEff — if all bits set 0000003fffffffff, container is privileged)
    • Host network mode (check: cat /proc/1/net/dev and compare to host — if identical, host networking is active)
    • Dangerous volume mounts: / or /home or /etc mounted from host (check: mount | grep -E "on / type|on /home type|on /etc type" for bind mounts from host)
  4. If --privileged or host root/home mounted: VERIFIED FAIL — any agent compromise is full host compromise
  5. If host network only: WARN
  6. If none of the above: PASS

Fix:

# Remove --privileged flag from docker run / docker-compose.yml
# Replace host volume mounts with specific directories:
#   BAD:  -v /:/host
#   GOOD: -v /path/to/project:/workspace:ro
# Use non-root user inside container:
#   USER 1000:1000 in Dockerfile
# Drop all capabilities and add only what's needed:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE ...

CLAW-09: Agent Running as Root

Severity CRITICAL (15 pts)
OWASP ASI-05 Unexpected Code Running
Ref If UID=0, any agent compromise = full system compromise
Verified Yes — checks process UID

What to check:

  1. Check the UID of the current process: run id -u
  2. If UID is 0 (root): VERIFIED FAIL — the agent has unrestricted system access
  3. Also check if the agent user has passwordless sudo: run sudo -n true 2>/dev/null — if it succeeds without prompting, the user effectively has root
  4. If UID != 0 and no passwordless sudo: VERIFIED PASS
  5. If UID != 0 but passwordless sudo exists: WARN

Fix:

# Create a dedicated non-root user for the agent:
sudo useradd -m -s /bin/bash openclaw-agent
# Run the agent as that user:
sudo -u openclaw-agent openclaw start
# Remove passwordless sudo if present:
sudo visudo  # Remove NOPASSWD entries for the agent user
# In Docker, add to Dockerfile:
RUN useradd -m agent
USER agent

CLAW-10: Sandbox Configuration

Severity HIGH (10 pts)
OWASP ASI-05 Unexpected Code Running
Ref OpenClaw sandbox is OFF by default (Issue #7827)

What to check:

  1. Read ~/.openclaw/openclaw.jsonsandbox.mode
  2. If off or not set: FAIL — agent code runs directly on host
  3. If non-main: WARN — only non-primary sessions sandboxed
  4. If all: check sandbox.scope:
    • shared: WARN — cross-session data leakage possible
    • session or agent: PASS

Fix:

openclaw config set sandbox.mode all
openclaw config set sandbox.scope session

CLAW-11: Elevated Mode Restrictions

Severity HIGH (10 pts)
OWASP ASI-05 Unexpected Code Running
CVE CVE-2026-25253 kill chain used elevated mode to escape sandbox

What to check:

  1. Read ~/.openclaw/openclaw.jsontools.elevated
  2. If tools.elevated.allowFrom is set to * or all: FAIL — sandbox escape for any session
  3. If tools.elevated exists but allowFrom is restricted to specific users/channels: PASS
  4. If tools.elevated doesn't exist: PASS (not configured)

Fix:

# Restrict elevated mode to specific trusted users only
openclaw config set tools.elevated.allowFrom '["your-telegram-id"]'
# Or disable entirely:
openclaw config delete tools.elevated

CLAW-12: Configuration File Permissions

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref CIS Benchmark: sensitive config should be 600
Verified Yes — checks actual file permissions

What to check:

  1. Check permissions on:
    • ~/.openclaw/openclaw.json
    • ~/.openclaw/.env
    • ~/.openclaw/credentials/ (all files)
    • ~/.openclaw/agents/*/agent/auth-profiles.json
  2. Any file readable by group or others (mode > 600 for files, > 700 for dirs): FAIL
  3. All files owner-only: PASS

Fix:

chmod 600 ~/.openclaw/openclaw.json ~/.openclaw/.env
chmod -R 600 ~/.openclaw/credentials/
chmod 700 ~/.openclaw/ ~/.openclaw/credentials/
# Or let openclaw fix it:
openclaw doctor --fix

CLAW-13: Installed Skills Against Threat Intel

Severity HIGH (10 pts)
OWASP ASI-04 Agentic Supply Chain
Ref 341 malicious ClawHub skills found (12% of registry), Feb 2026

What to check:

  1. List all skills in ~/.openclaw/skills/
  2. Check against known-malicious skills (case-insensitive):
    data-exfil, keylogger, reverse-shell, crypto-miner, credential-stealer,
    prompt-injector, shadow-agent, backdoor-tool, solana-wallet-tracker,
    polymarket-trader, token-sniper, atomic-stealer, openclaw-boost,
    free-credits, claw-premium, admin-tools
    
  3. Flag skills that:
    • Have no SKILL.md file
    • Were modified in the last 24 hours (potential tampering)
    • Have npm packages with post-install scripts
  4. If known-malicious found: VERIFIED FAIL
  5. If 3+ unverified (no SKILL.md): WARN
  6. If all clean: PASS

Fix:

# Remove malicious skills:
rm -rf ~/.openclaw/skills/<malicious-skill>
# Enable plugin allowlist (whitelist mode):
openclaw config set plugins.allow '["skill-a", "skill-b"]'

CLAW-14: MCP Server Known Vulnerabilities

Severity HIGH (10 pts)
OWASP ASI-04 Agentic Supply Chain
CVE CVE-2025-6514 (mcp-remote RCE, CVSS 9.6), CVE-2025-49596 (MCP Inspector RCE), CVE-2025-53109/53110 (Filesystem MCP escape)

What to check:

  1. Find installed MCP packages: check package.json files in agent config, node_modules/ directories, or MCP config
  2. Check versions against known-vulnerable:
    • mcp-remote < 1.1.0 → CVE-2025-6514 (CRITICAL)
    • @anthropic/mcp-inspector < 0.7.0 → CVE-2025-49596
    • @anthropic/mcp-server-filesystem < 2.1.0 → CVE-2025-53109
    • @anthropic/mcp-server-git < 2.1.0 → CVE-2025-68143/68144/68145
  3. If any vulnerable version found: FAIL — report package and CVE
  4. If no MCP packages found: SKIP
  5. If all patched: PASS

Fix:

npm update mcp-remote @anthropic/mcp-inspector @anthropic/mcp-server-filesystem
# Or pin to safe versions in package.json

CLAW-15: OpenClaw Version Security

Severity HIGH (10 pts)
CVE CVE-2026-25253 (CVSS 8.8) — patched in v2.6.1+

What to check:

  1. Run openclaw --version or read package.json
  2. Known-vulnerable versions:
    • < 2.6.1: CVE-2026-25253 (unauthenticated RCE)
    • < 2.5.0: Multiple path traversal issues
  3. If vulnerable: FAIL
  4. If current: PASS

Fix:

openclaw update
# Or:
npm install -g openclaw@latest

CLAW-16: Session File Permissions

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Session files contain full conversation history in plaintext JSONL
Verified Yes — checks actual permissions

What to check:

  1. Check permissions on ~/.openclaw/agents/*/sessions/ directories and files
  2. If any session file is readable by group or others: FAIL
  3. If all owner-only: PASS
  4. Also check: are session files being synced to cloud (iCloud, Dropbox, Google Drive)? If ~/.openclaw/ is inside a synced folder: WARN

Fix:

chmod -R 700 ~/.openclaw/agents/*/sessions/
# Exclude from cloud sync:
# macOS: add to .nosync or move outside ~/Library/Mobile Documents

CLAW-17: Default Credentials in Config

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Default/placeholder credentials are the first thing attackers try

What to check:

  1. Scan these files for default/placeholder values:
    • ~/.openclaw/openclaw.json
    • ~/.openclaw/.env
    • .env and openclaw.json in current directory
  2. Patterns to match (case-insensitive):
    • change_me, changeme
    • default, placeholder
    • example, sample
    • YOUR_ (e.g., YOUR_API_KEY, YOUR_TOKEN)
    • xxx, TODO, FIXME
    • password123, admin, test
    • Exact matches of documented default values from OpenClaw quickstart guides
  3. Only flag values that appear in key-value contexts (not comments or descriptions)
  4. If any default/placeholder values found in credential fields: FAIL
  5. If none found: PASS

Fix:

# Replace all placeholder values with real credentials:
openclaw config set gateway.auth.token "$(openssl rand -hex 32)"
# Audit your .env file:
grep -inE "change_me|default|placeholder|YOUR_|xxx" ~/.openclaw/.env
# Replace each match with actual values, then:
chmod 600 ~/.openclaw/.env

CLAW-18: .env Not in .gitignore

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Wiz research: 65% of Forbes AI 50 companies leaked secrets on GitHub
Verified Yes — checks .gitignore contents

What to check:

  1. Check if the current directory or ~/.openclaw/ is inside a git repository: run git rev-parse --is-inside-work-tree 2>/dev/null
  2. If not a git repo: SKIP
  3. If it is a git repo, check if .env is listed in .gitignore:
    • Run git check-ignore .env — if it returns .env, it's ignored: PASS
    • Also check for .env*, .env.local, .env.production patterns
  4. If .env is NOT ignored: FAIL — secrets may be committed to version control
  5. Bonus: check if .env is already tracked by git: git ls-files --error-unmatch .env 2>/dev/null — if tracked, it's already in history even if later added to .gitignore

Fix:

# Add .env to .gitignore:
echo ".env" >> .gitignore
echo ".env.*" >> .gitignore
# If .env was already committed, remove from tracking (file stays on disk):
git rm --cached .env
git commit -m "Remove .env from tracking"
# WARNING: The .env is still in git history — see CLAW-19

CLAW-19: Secrets in Git History

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Keys committed even once persist in history forever; Wiz found secrets in deleted forks and gists
Verified Yes — scans actual git log

OPT-IN: Ask the user before running this check:

"Check 20 scans your git history for accidentally committed secrets (API keys, tokens). This may take a moment on large repos. Run this check? (y/n)"

If declined: SKIP (-1)

What to check:

  1. Check if current directory is a git repo: git rev-parse --is-inside-work-tree 2>/dev/null
  2. If not a git repo: SKIP
  3. Scan recent git history (last 100 commits) for secret patterns:
    git log --all -p -100 2>/dev/null
    
  4. Search output for the same API key patterns as CLAW-05:
    • sk- followed by 20+ alphanumeric chars
    • sk-ant- (Anthropic)
    • AKIA followed by 16 uppercase alphanumeric chars (AWS)
    • ghp_ followed by 36 alphanumeric chars (GitHub)
    • xoxb- or xoxp- (Slack)
    • Lines matching (?i)(api[_-]?key|secret|token|password)\s*[=:]\s*['"]?[a-zA-Z0-9_\-]{20,}
  5. If secrets found in history: VERIFIED FAIL — report count and commit range, never the actual values
  6. If no secrets found: PASS

Fix:

# IMPORTANT: Rotate all exposed credentials FIRST — assume they are compromised
# Then remove from history using git-filter-repo (preferred over BFG):
pip install git-filter-repo
git filter-repo --invert-paths --path .env --force
# Or use BFG Repo Cleaner:
bfg --delete-files .env
git reflog expire --expire=now --all && git gc --prune=now --aggressive
# Force push the cleaned history (coordinate with team):
git push --force-with-lease

CLAW-20: Browser Profiles Accessible

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Browser profiles contain saved passwords, cookies, and active session tokens for every logged-in service
Verified Yes — checks if directories are readable

What to check:

  1. Check if any of the following browser profile directories exist AND are readable:
    # macOS
    ~/Library/Application Support/Google/Chrome/
    ~/Library/Application Support/Firefox/Profiles/
    ~/Library/Application Support/BraveSoftware/Brave-Browser/
    ~/Library/Application Support/Microsoft Edge/
    # Linux
    ~/.config/google-chrome/
    ~/.mozilla/firefox/
    ~/.config/BraveSoftware/Brave-Browser/
    ~/.config/microsoft-edge/
    
  2. For each path, run test -r <path> (or equivalent stat check)
  3. If 2+ browser profile directories are readable: VERIFIED FAIL — agent can access saved passwords, cookies, session tokens
  4. If 1 readable: WARN
  5. If none readable: VERIFIED PASS

Report which browser profiles are exposed but never read their contents.

Fix:

# Enable sandbox to isolate agent from browser profile directories
openclaw config set sandbox.mode all
# Or restrict permissions (will break browser for current user — use sandbox instead):
# The real fix is running the agent as a separate user:
sudo -u openclaw-agent openclaw start

CLAW-21: Git Credentials Accessible

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Plaintext git credentials give push access to every repository the user has access to
Verified Yes — checks if credential files are readable

What to check:

  1. Check if the following files exist AND are readable:
    ~/.git-credentials
    ~/.gitconfig
    
  2. For ~/.git-credentials: if it exists and is readable: FAIL — contains plaintext username:token pairs
  3. For ~/.gitconfig: check if it contains a credential section with helper = store (plaintext storage): if so, FAIL
  4. Also check for credential helpers that cache tokens:
    • git config --global credential.helper — if set to store, credentials are in plaintext
    • If set to cache, credentials are temporarily in memory (less severe)
    • If set to osxkeychain, wincred, or libsecret: PASS (uses OS keychain)
  5. If no plaintext credential storage found: PASS

Fix:

# Switch from plaintext to OS keychain:
# macOS:
git config --global credential.helper osxkeychain
# Linux:
git config --global credential.helper libsecret
# Remove plaintext credentials file:
rm ~/.git-credentials
# Enable agent sandbox to prevent access:
openclaw config set sandbox.mode all

CLAW-22: Database Credentials Accessible

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Database credential files provide direct access to production data
Verified Yes — checks if credential files are readable

What to check:

  1. Check if the following database credential files exist AND are readable:
    ~/.pgpass                          # PostgreSQL
    ~/.my.cnf                          # MySQL/MariaDB
    ~/.mongosh/                        # MongoDB Shell history/config
    ~/.config/redis/                   # Redis config
    ~/.influxdbv2/configs              # InfluxDB
    ~/.cqlshrc                         # Cassandra
    
  2. For each, run test -r <path> (or equivalent stat check)
  3. If 2+ database credential paths are readable: VERIFIED FAIL — agent can directly access databases
  4. If 1 readable: WARN
  5. If none readable: VERIFIED PASS

Report which credential files are exposed but never read their contents.

Fix:

# Restrict permissions on database credential files:
chmod 600 ~/.pgpass ~/.my.cnf ~/.cqlshrc 2>/dev/null
chmod 700 ~/.mongosh/ ~/.config/redis/ 2>/dev/null
# Enable sandbox to isolate agent:
openclaw config set sandbox.mode all
# Best practice: use a separate user for the agent:
sudo -u openclaw-agent openclaw start

CLAW-23: Additional Services on 0.0.0.0

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref AutoGPT exposes ports 8000+3000 by default; 17,500+ OpenClaw instances found exposed
Verified Yes — checks actual listening sockets

What to check:

  1. List all services bound to all interfaces:
    ss -tlnp 2>/dev/null | grep "0.0.0.0" || netstat -tlnp 2>/dev/null | grep "0.0.0.0"
    
  2. Flag any agent-related services on well-known ports bound to 0.0.0.0:
    • Port 3000 (web UI frontend)
    • Port 5000 (Flask/API server)
    • Port 8000 (AutoGPT/agent web UI)
    • Port 8080 (HTTP proxy/alternate web UI)
    • Port 18789 (OpenClaw gateway — also covered by CLAW-01)
    • Any port in the range 3000-9999 with agent-related process names
  3. If 2+ agent services bound to 0.0.0.0: VERIFIED FAIL
  4. If 1 agent service on 0.0.0.0 (besides gateway, which is CLAW-01): WARN
  5. If all agent services bound to 127.0.0.1/localhost: PASS
  6. If no additional agent services found: SKIP

Fix:

# Bind services to localhost only:
# In docker-compose.yml, change:
#   ports: ["8000:8000"]     →   ports: ["127.0.0.1:8000:8000"]
#   ports: ["3000:3000"]     →   ports: ["127.0.0.1:3000:3000"]
# In agent config, set bind address to 127.0.0.1
# Use a reverse proxy (nginx/caddy) with auth for remote access

CLAW-24: No Firewall Rules

Severity HIGH (10 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Without a firewall, every exposed port is reachable from the network
Verified Yes — checks firewall status

What to check:

  1. Check for active firewall rules on the system:
    # Linux:
    sudo iptables -L -n 2>/dev/null | grep -c "^[A-Z]"
    sudo ufw status 2>/dev/null
    sudo nft list ruleset 2>/dev/null | head -5
    # macOS:
    sudo pfctl -s rules 2>/dev/null | head -5
    /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate 2>/dev/null
    
  2. If no firewall is active and no rules are configured: FAIL — every listening port is reachable
  3. If a firewall is active but has no restrictive rules (only default ACCEPT policies): WARN
  4. If a firewall is active with restrictive rules: PASS
  5. If the system is a local development machine (not a VPS/server): SKIP — home router typically provides NAT

To determine if this is a VPS: check if running on a cloud provider (metadata service responds, or hostname contains common cloud patterns like ip-, .compute., .ec2.).

Fix:

# Linux (ufw — simplest):
sudo ufw default deny incoming
sudo ufw allow ssh
sudo ufw enable
# Linux (iptables):
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -j DROP
# macOS:
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on

CLAW-25: Container Security Profile

Severity HIGH (10 pts)
OWASP ASI-05 Unexpected Code Running
CVE CVE-2025-31133, CVE-2025-52565, CVE-2025-52881 (runC container escape vulnerabilities)
Verified Yes — inspects container security configuration

What to check:

  1. Detect if running inside Docker: check for /.dockerenv file or cgroup entries
  2. If not in Docker: SKIP
  3. Check for seccomp profile:
    • Run: grep -c Seccomp /proc/1/status — if Seccomp: 0, no seccomp profile is applied
    • Seccomp: 2 means a filter is active: PASS for seccomp
  4. Check for AppArmor profile:
    • Run: cat /proc/1/attr/current 2>/dev/null — if unconfined, no AppArmor profile
    • If a named profile is listed: PASS for AppArmor
  5. Check runC version:
    • runc --version 2>/dev/null — vulnerable if below 1.2.8, 1.3.3, or 1.4.0-rc.3
  6. If no seccomp AND no AppArmor profile: VERIFIED FAIL — container has minimal syscall restrictions
  7. If only one of seccomp/AppArmor: WARN
  8. If both active and runC patched: PASS

Fix:

# Apply Docker's default seccomp profile (enabled by default unless --security-opt seccomp=unconfined):
# In docker-compose.yml:
#   security_opt:
#     - seccomp:default
#     - no-new-privileges:true
# Update runC to patched version:
sudo apt update && sudo apt install runc
# Or update Docker Engine which bundles runC:
sudo apt update && sudo apt install docker-ce docker-ce-cli

CLAW-26: Agent Code Integrity

Severity HIGH (10 pts)
OWASP ASI-04 Agentic Supply Chain
Ref Uncommitted modifications to agent code could indicate backdoors or tampering
Verified Yes — checks git status of agent installation

What to check:

  1. Find the OpenClaw installation directory:
    • Check which openclaw or npm list -g openclaw
    • Common paths: /usr/lib/node_modules/openclaw/, /usr/local/lib/node_modules/openclaw/, or local node_modules/openclaw/
  2. If the installation directory is a git repo (or contains .git):
    • Run: git -C <install_dir> status --porcelain 2>/dev/null
    • If there are modified files: FAIL — agent source has been modified from the official release
    • Run: git -C <install_dir> diff 2>/dev/null | head -50 — report which files changed (not the full diff content)
  3. If installed via npm (no .git directory): verify package integrity:
    • Run: npm ls openclaw and check the installed version matches expected
  4. If no modifications detected: PASS
  5. If installation directory not found: SKIP

Fix:

# Reinstall from official source:
npm install -g openclaw@latest
# Verify integrity after install:
npm audit signatures
# To prevent future tampering, make install directory read-only:
sudo chmod -R a-w /usr/lib/node_modules/openclaw/

CLAW-27: npm Post-Install Scripts in Skills

Severity HIGH (10 pts)
OWASP ASI-04 Agentic Supply Chain
Ref ClawHub supply chain attacks: 341 malicious skills used post-install scripts to deliver Atomic Stealer malware
Verified Yes — scans actual package.json files

What to check:

  1. For each skill directory in ~/.openclaw/skills/*/:
    • Check if a package.json file exists
    • If it does, scan for lifecycle scripts:
      preinstall, install, postinstall,
      preuninstall, uninstall, postuninstall,
      prepack, postpack, prepare
      
    • These scripts run automatically with full user privileges during npm install
  2. If any skill has preinstall or postinstall scripts: FAIL — report which skills and which scripts
  3. If skills have other lifecycle scripts (prepare, prepack): WARN
  4. If no lifecycle scripts found in any skill: PASS
  5. If no skills have package.json: SKIP

Fix:

# Remove suspicious skills:
rm -rf ~/.openclaw/skills/<suspicious-skill>
# Disable npm lifecycle scripts globally (nuclear option):
npm config set ignore-scripts true
# Or audit before installing:
npm install --ignore-scripts  # Then manually review what scripts would run
# Enable OpenClaw plugin allowlist:
openclaw config set plugins.allow '["trusted-skill-1", "trusted-skill-2"]'

CLAW-28: Log Redaction Configuration

Severity MEDIUM (5 pts)
CVE CVE-2026-22038 (AutoGPT plaintext key logging)
Ref Secrets in logs are the #1 accidental exposure vector

What to check:

  1. Read ~/.openclaw/openclaw.jsonlogging.redactSensitive
  2. If not set or set to off: FAIL
  3. If set to tools (default): PASS
  4. Bonus: check if logging.redactPatterns has custom patterns for the user's specific API key formats

Fix:

openclaw config set logging.redactSensitive tools

CLAW-29: Debug Logging Enabled

Severity MEDIUM (5 pts)
CVE CVE-2026-22038 (AutoGPT plaintext key logging)
Ref Debug mode leaks extra data including full request/response payloads with auth headers and API keys

What to check:

  1. Read ~/.openclaw/openclaw.jsonlogging.level
  2. Also check environment variables: OPENCLAW_LOG_LEVEL, DEBUG, NODE_DEBUG, LOG_LEVEL
  3. If logging level is set to debug, verbose, or trace: FAIL — full request/response payloads (including API keys in headers) will be written to logs
  4. If DEBUG=* or DEBUG=openclaw:* is set in environment or .env: FAIL
  5. If logging level is info, warn, or error: PASS
  6. If not explicitly set (defaults apply): PASS

Fix:

# Set logging to production-appropriate level:
openclaw config set logging.level warn
# Remove debug environment variables:
# In ~/.openclaw/.env, remove or comment out:
#   DEBUG=*
#   OPENCLAW_LOG_LEVEL=debug
#   NODE_DEBUG=*
# Also ensure log redaction is enabled (see CLAW-28):
openclaw config set logging.redactSensitive tools

CLAW-30: Sessions Synced to Cloud

Severity MEDIUM (5 pts)
OWASP ASI-03 Identity & Privilege Abuse
Ref Session history contains conversation data, tool outputs, and potentially leaked secrets — cloud sync uploads this to third-party servers

What to check:

  1. Resolve the real path of ~/.openclaw/: realpath ~/.openclaw/
  2. Check if the resolved path falls inside any known cloud sync folder:
    # macOS iCloud:
    ~/Library/Mobile Documents/
    # Dropbox:
    ~/Dropbox/
    # Google Drive:
    ~/Google Drive/
    ~/Library/CloudStorage/GoogleDrive-*/
    # OneDrive:
    ~/OneDrive/
    ~/Library/CloudStorage/OneDrive-*/
    
  3. Also check if ~/.openclaw/ itself is a symlink pointing into a sync folder
  4. If ~/.openclaw/ is inside a cloud sync folder: FAIL — all session data, configs, and credentials are being uploaded to the cloud provider
  5. If not inside any sync folder: PASS

Fix:

# Move .openclaw out of the synced folder:
mv ~/.openclaw /usr/local/var/openclaw
ln -s /usr/local/var/openclaw ~/.openclaw
# Or exclude from sync:
# macOS iCloud: add .nosync extension or use .nosync file
touch ~/.openclaw/.nosync
# Dropbox: use selective sync to exclude .openclaw
# Google Drive: use selective sync settings in Drive app

Scoring

Weights

Severity Points per check Count
CRITICAL 15 21 checks
HIGH 10 43 checks
MEDIUM 5 8 checks
Total 785 72 checks

Calculation

score = (sum of points for PASSED checks) / (sum of points for all NON-SKIPPED checks) x 100

Skipped checks (opt-in declined, not applicable) are excluded from both numerator and denominator.

WARN results count as half points (e.g., a HIGH check with WARN = 5 points instead of 10).

Grade

Grade Score Meaning
A 90-100 Hardened — no critical findings
B 75-89 Good — minor improvements needed
C 60-74 Needs work — some real risks
D 40-59 Exposed — significant vulnerabilities
F 0-39 Critical — immediate action required

Output Format

Present results as:

## Have I Been Clawned? — Security Audit

### Hardening Score: [SCORE]/100 — Grade [GRADE]
[████████░░] 80/100

| # | Check | Result | Severity | Ref |
|---|-------|--------|----------|-----|
| 01 | Gateway Network Exposure | ✅ VERIFIED PASS | CRITICAL | CVE-2026-25253 |
| 02 | Gateway Authentication | ❌ VERIFIED FAIL | CRITICAL | CVE-2026-25253 |
| ... | ... | ... | ... | ... |

### Findings

#### ❌ CLAW-02: Gateway Authentication — VERIFIED FAIL
**Why it matters:** Without authentication, anyone who can reach your gateway port can
control your agent and access stored API tokens. 17,500+ OpenClaw instances were found
exposed this way (CVE-2026-25253).

**Fix:**
\`\`\`bash
openclaw config set gateway.auth.mode token
openclaw config set gateway.auth.token "$(openssl rand -hex 32)"
\`\`\`

[Repeat for each failing check]

### Share your results
[SHAREABLE_URL]

Shareable Report URL

Encode results as JSON, then base64url. The URL contains everything — no backend storage needed.

const report = {
  v: 3,                // format version
  s: 72,               // hardening score
  g: "C",              // grade
  r: [1,0,1,...],  // 72 results, ordered by check #
  // Values: 1=pass, 0=fail, 2=warn, -1=skip
  t: "2026-02-07"      // date
};
const encoded = btoa(JSON.stringify(report))
  .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
const url = `https://haveibeenclawned.com/report?d=${encoded}`;

Show to the user:

Share your results: [URL]


Anonymous Stats (Opt-in)

If using the script, ask the user to re-run with --submit (see "How to run" above).

If running checks individually, POST to https://haveibeenclawned.com/api/submit:

{
  "v": 3,
  "s": 72,
  "g": "C",
  "r": [1,0,1,...]
}

Contributing

This audit is open source. Add checks, update threat intel, improve fix commands.

Rule format

Each check follows this structure:

### CLAW-XX: Check Name
| | |
|---|---|
| **Severity** | CRITICAL (15 pts) / HIGH (10 pts) / MEDIUM (5 pts) |
| **OWASP** | ASI-XX Reference |
| **CVE** | CVE-XXXX-XXXXX (if applicable) |
| **Verified** | Yes/No — does this check actually test the vulnerability? |

**What to check:**
[Step-by-step instructions an AI agent can follow]

**Fix:**
[Exact commands to remediate]

How to contribute

  1. Fork github.com/wadim/haveibeenclawned
  2. Add your check to SKILL.md following the format above
  3. Update the check count (currently 72), scoring weights, and report encoding
  4. Open a PR with:
    • The new check
    • A reference (CVE, blog post, research paper)
    • Why this check matters (real-world impact)

Threat intel updates

The known-malicious skills list and CVE version checks are updated regularly. To suggest additions, open an issue with the source reference.