๐Ÿ  Home โ† Docs Index
Open Beta ๐Ÿ“– Interactive Reader Raw .md llms.txt

Security + Exec Approval

GoClaw implements deep application-level security across multiple layers: path sandboxing, shell/HTTP allowlists, SSRF protection, PBKDF2 encryption, skill security scanning, SAST analysis, ingress IP allowlisting, and gateway auth.

Security Architecture

flowchart TD
    subgraph SEC["GoClaw Security Layers"]
        GW["<b>Gateway</b><br/>Auth + Rate limit<br/>trustProxy ยท IP allowlist"]
        TOOL["<b>Tool-level</b><br/>Sandboxing<br/>Path / Shell ยท HTTP policy"]
        DATA["<b>Data-at-rest</b><br/>Encryption<br/>AES-256-GCM ยท PBKDF2 (600K)"]

        NET["<b>Network</b><br/>SSRF block<br/>Domain WL ยท Private IP"]
        CODE["<b>Code</b><br/>SAST scan<br/>Linter ยท gosec / ruff"]
        CONT["<b>Content</b><br/>Skill scanner<br/>Rule-based ยท Prompt inject"]

        GW --> NET
        TOOL --> CODE
        DATA --> CONT
    end

Security Features

# Feature OpenClaw GoClaw Status
7.1 Path sandboxing Workspace isolation resolveFilePath() โ€” path traversal blocked, all paths resolved within workspace Done
7.2 Shell command allowlist Permission system tools.shell.allow / tools.shell.deny in config. Empty allow = all blocked. Deny checked first. Entries match by prefix (git also matches gitk). A command containing a shell metacharacter (; & | $ > < ` \ ! ( ) { } [ ] = # ^ % @ or a newline) is refused even with allow: ["*"]. Hardcoded deny patterns, matched anywhere in the command and case-insensitively: destructive commands (rm -rf /, dd if=, mkfs., format ), shutdown/reboot, Ansible, make deploy/install/update/restart and similar targets, service management (systemctl, launchctl, service), ssh/scp, system package installs, user management, Windows registry and firewall changes Done
7.3 DM pairing system Device pairing (web) Pairing code for Discord/Teams DMs; approve on the Web UI's Pairing tab. A CLI approval made while the gateway runs reaches it only after a restart Done
7.4 DM policy modes Per-channel config dm_policy: pairing (default), allowlist, open Done
7.5 Guild channel isolation Channel allowlists Bot only responds to @mentions or direct replies in Discord guilds Done
7.6 Read-only database queries โ€” db_query allows only SELECT/SHOW/DESCRIBE/EXPLAIN. INSERT/UPDATE/DELETE blocked. Writes go through db_write, only on datasources with allow_write: true, only for admins and SOP/cron runs (not webhook-triggered or delegated runs), capped at tools.max_db_write_rows rows per call. metrics_store writes its own agent_metrics table on a datasource only with allow_write, for an admin or admin-authored SOP/cron run (not webhook-triggered or delegated runs); its first write creates the table, and its writes are not row-capped Done
7.7 Query timeout + row limits โ€” 30s timeout, which the database enforces too: about 29s on PostgreSQL and MySQL/MariaDB, and on ClickHouse where the account lets goclaw set max_execution_time (otherwise the profile's own); max 10,000 rows (tools.max_db_query_rows), max 1000 chars per cell Done
7.7a Read-only on the database โ€” db_query reads in a read-only PostgreSQL transaction; on MySQL/MariaDB with the connection's session set to transaction_read_only=1 for the read (a read-only transaction alone still runs DDL); on ClickHouse with readonly=1 where the account allows it (writes and SET refused; url()/file()/remote() stay refused by goclaw's checks, since DESCRIBE TABLE url(โ€ฆ) still connects out). db_query's SQL never runs on PostgreSQL's simple protocol, which would run several statements from one query Done
7.8 HTTP response size limit โ€” http_request caps response body at 100KB Done
7.9 Tool loop safety โ€” tools.max_tool_iterations (default 20) prevents infinite LLM tool loops Done
7.10 Dangerous command hardcodes โ€” Fork bombs, disk wipes, shutdown commands blocked regardless of config Done
7.11 Git write gating โ€” Read ops always allowed, write ops require config flag, dangerous ops always blocked Done
7.12 File edit safety โ€” file_edit requires unique string match โ€” no mass replacements Done
7.13 Bootstrap file protection Read-only MEMORY.md For anyone but an admin or a SOP/cron run, file_write/file_edit block writes to MEMORY.md, SOUL.md, TOOLS.md, AGENTS.md, IDENTITY.md, USER.md, subagent profiles (*.agent.md) and instructions (*.instructions.md). No file tool writes inside a .git directory Done
7.14 Gateway auth (token) OAuth / device code X-GoClaw-Token header, Bearer auth, health probes exempt Done
7.15 Rate limiting โ€” Per-IP token bucket middleware, configurable gateway.rate_limit.per_minute Done
7.16 Secrets encryption Credential store AES-256-GCM vault + PBKDF2 key derivation (600K iterations) Done
7.17 Trust proxy โ€” gateway.ingress.trust_proxy (and gateway.rate_limit.trust_proxy) โ€” only reads X-Forwarded-For when trusted, and then its last entry, the one the proxy wrote. Used by the ingress allowlist, the rate limits (gateway and App API) and the audit log. Prevents IP spoofing Done
7.18 HTTP default-deny policy โ€” nginx-style: empty allow list blocks all external HTTP. default_policy: deny|allow Done (GoClaw only)
7.19 SSRF protection โ€” DNS-level private IP blocking (0.x, 10.x, 100.64-127.x, 172.16-31.x, 192.168.x, loopback, link-local, ULA IPv6) Done (GoClaw only)
7.20 Domain whitelist/blacklist โ€” tools.http.allow / tools.http.deny with wildcard (*.mn), CIDR, exact match Done (GoClaw only)
7.21 Internal hostname bypass โ€” Allowlisted hostnames that resolve to private IPs are permitted (e.g. monitor.example.mn โ†’ 10.0.2.7). A wildcard entry counts: see Bypass Mechanisms Done (GoClaw only)
7.22 Per-agent HTTP scope โ€” Agent-level tools.http.allow/deny overrides global policy via runtimeScope Done (GoClaw only)
7.22a Hosts per run โ€” tools.http.max_hosts_per_run (default 100): one agent run, its subagents included, reaches at most that many different hosts through SafeHTTPClient; the next new host is refused and logged. A start-up warning names shell.allow: ["*"] or an open default_policy: allow on a gateway other machines can reach Done (GoClaw only)
7.23 Pre-flight URL validation โ€” ValidateURL() โ€” domain policy + SSRF check before the browser tools navigate and before notify posts to a webhook URL. Other tools' requests are checked when they connect (SafeHTTPClient) Done (GoClaw only)
7.24 Skill Security Scanner โ€” Rules for prompt injection in skill text and dangerous code patterns. Blocks critical findings on install Done (GoClaw only)
7.25 SAST Scanner โ€” run_sast_scanner tool โ€” runs gosec (Go) or bandit (Python) on workspace code; the scanner must be installed on the host Done (GoClaw only)
7.26 Code Linter โ€” run_code_linter tool โ€” runs golangci-lint (Go), ruff (Python) or dart analyze (Dart/Flutter); the linter must be installed on the host Done (GoClaw only)
7.27 Ingress IP allowlist โ€” Webhook ingress: M365 preset auto-fetch or explicit IPs/CIDRs + access logging (see below) Done (GoClaw only)
7.28 Memory write RBAC โ€” memory_write: personal scope for any identified (paired) user, never from SOP/cron/webhook runs; agent_notes and agent_config for admins and the roles/users listed under memory.write_access (SOP/cron/webhook runs may write agent_notes only, never global or agent_config); global: while memory.write_access is enabled (the default, with allowed_roles: [system]), only the roles and users it lists; with it disabled, admins. memory_consolidate: admins and SOP/cron runs. update_core_instruction: a human admin only Done
7.29 isHumanAdmin Check โ€” Critical actions (altering identity, persona) require a real human admin โ€” automated SOP/Cron runs are blocked. Done (GoClaw only)
7.30 Rollback Safety โ€” SOP rollback commands are validated against the shell allowlist to prevent privilege escalation. Done (GoClaw only)
7.31 Docker sandboxing Docker-based isolation โ€” TODO

SSRF Protection Detail (safe_client.go)

GoClaw's SafeHTTPClient implements DNS-level SSRF protection at the transport layer:

flowchart LR
    REQ["HTTP Request"] --> DOM["<b>Domain Filter</b>"]
    DOM -->|"Pass"| DNS["<b>DNS Resolve</b>"]
    DNS --> IP["<b>Private IP Check</b>"]
    IP -->|"Public / Allowed"| CONN["<b>Connect</b>"]

    DOM -->|"Deny list / Not in allow /<br/>default_policy=deny + empty allow"| B1["<b>BLOCK</b>"]
    IP -->|"10.x / 172.16-31.x / 192.168.x /<br/>loopback / link-local / IPv6 ULA"| B2["<b>BLOCK</b>"]

Private IP Ranges Blocked

Range Description
0.0.0.0/8 "This host" (a connect to 0.0.0.0 reaches loopback)
10.0.0.0/8 Class A private
100.64.0.0/10 Carrier-grade NAT
172.16.0.0/12 Class B private
192.168.0.0/16 Class C private
127.0.0.0/8, ::1 Loopback
169.254.0.0/16, fe80::/10 Link-local
fc00::/7 IPv6 Unique Local Address

Bypass Mechanisms

HTTP Default-Deny Policy

tools:
  http:
    default_policy: "deny"   # "deny" (default) or "allow"
    allow:
      - "*.googleapis.com"
      - "api.github.com"
      - "monitor.example.mn"           # internal hostname โ†’ private IP allowed
      - "10.0.2.0/24"      # explicit CIDR allowlist (URLs with an IP host only)
    deny:
      - "127.0.0.1"
      - "*.internal"

Domain Matching

Pattern Matches
* All domains, private addresses included
*.mn example.mn, sub.example.mn, including names that resolve to private addresses
api.github.com Exact match only
10.0.2.0/24 CIDR range, for URLs whose host is an IP address
192.168.1.1 Exact IP, for URLs whose host is that IP

Skill Security Scanner

Layer Rules Detects
Prompt Injection prompt-override, role-injection, jailbreak-attempt, shell-danger-in-skill, secret-extraction, hidden-instruction, invisible-unicode, data-exfil-url LLM manipulation, curl|bash, credential theft, instructions hidden in HTML comments or zero-width characters
Code Patterns dangerous-exec, dynamic-code-exec, crypto-mining, reverse-shell, env-harvesting, potential-exfiltration, obfuscated-hex, obfuscated-base64, suspicious-network Shell injection, mining, exfiltration

Ingress IP Allowlist (MS Teams)

Feature Description
M365 preset gateway.ingress.allow_preset: microsoft-teams fetches the Microsoft 365 Skype/Teams IPv4 ranges from endpoints.office.com at startup. If the fetch fails, the gateway does not start
Explicit IPs Direct IP addresses in gateway.ingress.allow_ips. A non-empty allow_ips replaces the preset: the two are not combined
CIDR ranges Network ranges (e.g. 52.112.0.0/14)
Scope Without gateway.ingress.port the webhooks share the main port, and the allowlist then applies to the whole gateway, Web UI included. Set gateway.ingress.port to keep it to the webhook listener
Loopback Requests from 127.0.0.0/8 and ::1 are always let through (CLI, local health probes)
Access logging Every request logged via runtimeinfo.RecordIngressAccess()
Denied tracking runtimeinfo.RecordIngressDenied() for monitoring
Web UI display Gateway tab shows access logs table

Exec Approval (Section 19)

GoClaw's interactive approval covers SOP steps only. A step marked requires_approval: true waits for an approval made through the gateway API; everything else is governed by the allow/deny lists.

# Feature OpenClaw GoClaw Status
19.1 Approval policy security (deny/allowlist/full) Shell allowlist + HTTP domain policy + per-agent scopes Done
19.2 Control UI approval Visual approve/deny in web panel No dashboard control. A SOP step marked requires_approval: true is approved or rejected with POST /api/sop/approve ({"job_id": "โ€ฆ", "action": "approve"} or "reject" with a "reason") and the gateway token. A step still waiting after 1 hour fails. Partial
19.3 macOS app approval Native dialog โ€” TODO
19.4 Channel approval /approve <id> โ€” (no chat or CLI command approves a step) TODO
19.5 Allowlist persistence exec-approvals.json config.yaml based allow/deny lists with hot-reload support. Done
19.6 Safe bins auto-allow Known safe commands pre-approved Hardcoded deny patterns + skill bin-check Partial
19.7 Skill CLI auto-allow Skills register their CLIs as safe โ€” TODO
19.8 Approval forwarding Route approval prompts to channels A step waiting for approval sends a notice to the channel and target set in sop.alerts (else only to the log). The notice carries the job ID to pass to the API; the sop approve <id> it suggests is not a command. Done (GoClaw only)

OpenClaw vs GoClaw Security Comparison

Aspect OpenClaw GoClaw
Sandboxing model Docker container isolation Application-level (path, shell, HTTP, IP)
HTTP policy No default-deny nginx-style default-deny
SSRF protection โ€” DNS-level private IP blocking
Domain filtering โ€” Wildcard + CIDR + hostname matching
Secret encryption Credential store AES-256-GCM + PBKDF2 (600K iterations)
Skill scanning โ€” Rule-based security scanner
Code analysis โ€” SAST scanner + code linter (gosec, bandit, golangci-lint, ruff)
Ingress security โ€” M365 IP preset + CIDR allowlist + access logs
Memory RBAC โ€” Admin-only write for core tools
Interactive approval Multi-surface (web, macOS, channel) SOP step approval through the API; otherwise shell/HTTP allowlists
Per-agent scopes โ€” Agent-level HTTP policy overrides

GoClaw security philosophy: Defense in depth at the application layer โ€” no Docker dependency for security. Every tool has its own safety boundary (path traversal, SQL injection, SSRF, shell injection) with configurable allow/deny policies.

Coverage: the security features above are in place except Docker sandboxing; exec approval is limited to SOP steps approved through the API.