-
-
Notifications
You must be signed in to change notification settings - Fork 52.9k
Description
Type: Feature Request
Category: feature-request
Severity: Critical
Problem Statement
OpenClaw's core architecture includes partial security mechanisms (network binding, Token/password auth, Scope authorization, tool policy allowlists, path sandbox), but these are fragmented, inconsistently applied, and not enforced in the plugin/skill subsystem. All 31+ plugins share a single Node.js process with no process isolation, no memory isolation, and no filesystem isolation. A vulnerability in any single plugin compromises the entire system — including all credentials, data stores, and 250+ SDK APIs. The existing sandbox design (e.g., clawd/sandbox.js path restrictions) has known bypass vulnerabilities (ECO-009). Most critically, there are no user-friendly default presets — requiring users to manually configure security, which most users (especially non-technical ones) never do.
This issue consolidates all sandbox and isolation deficiencies across the ecosystem:
- Former CSD-001 (No Plugin Sandbox Isolation)
- Former CSD-002 (Cross-Plugin Credential Exposure via Shared process.env)
- ECO-004 (Plugin Lateral Movement via Shared Process Model)
- ECO-005 (Credential Exposure via Shared Environment)
- ECO-009 (Sandbox Path Traversal — existing sandbox bypass)
- ECO-014 (Cross-Plugin Credential Leak)
- ECO-040 (Coding Agent Resource Exhaustion)
- ECO-045 (Agent Resource Exhaustion Loops)
- ECO-050 (Unrestricted Tool Execution)
Current State
Architectural Root Cause
OpenClaw loads all 31+ plugins via the jiti (Just-In-Time TypeScript) dynamic loader into a single Node.js process. Every plugin has unrestricted access to:
process.env— all 25+ service credentials (Slack, Telegram, OpenAI, Discord, Nostr, blockchain private keys, WeChat AES keys, etc.)- Full filesystem — no mount isolation
- All network connections — no outbound filtering
- 250+ SDK APIs — no per-plugin capability restrictions
- All other plugins' memory space — no V8 Isolate boundaries
Existing Partial Sandbox
The clawd/sandbox.js implements basic path restrictions for the sandbox:// URL scheme, but:
- Path traversal bypass exists (ECO-009, CVSS 9.3)
- No process-level isolation
- No credential scoping
- No network restrictions
- Not applied to plugins or skills
- Linux-only — no macOS or Windows equivalent
User Impact
Non-technical users ("beginners") have no way to configure sandbox policies. There are no preset security levels, no guided setup, and no defaults that provide meaningful protection. The result is that security is effectively opt-in and zero users opt in.
Impact Analysis
- Affected Components: All 31+ extensions, all bundled skills, all community plugins, all ClawHub skills (4,525+)
- Attack Surface: Any plugin vulnerability becomes system-wide. Cross-plugin lateral movement is trivial (ECO-004). Single credential read grants access to all 25+ integrated services (ECO-005, ECO-014).
- CVSS Impact: Addresses 9 ECO vulnerabilities with CVSS scores ranging 7.0-9.8, plus the CSD-001/002 architectural defect chain
- Related Issues: CSD-003, CSD-004, CSD-005, CSD-006, CSD-008, ECO-004, ECO-005, ECO-009, ECO-014, ECO-040, ECO-045, ECO-050
Proposed Solution
Design Principles
- Secure by Default: New installations ship with a reasonable sandbox preset enabled — users must opt DOWN, not opt UP
- Multi-Platform: Abstract sandbox primitives behind a unified configuration layer; map to platform-native isolation mechanisms
- Tiered Presets: 3-4 named security levels that non-technical users can select with a single setting
- Progressive Enforcement: Start with the lightest viable isolation, allow upgrading without architecture changes
Multi-Platform Sandbox Architecture
Abstraction Layer
A unified SandboxManager that exposes platform-agnostic capabilities:
| Capability | Description | Configuration Key |
|---|---|---|
| Process Isolation | Plugin runs in a separate process | sandbox.process: true |
| Filesystem Restriction | Read/write limited to declared paths | sandbox.fs.allow: [...] |
| Network Restriction | Outbound connections limited to declared hosts | sandbox.net.allow: [...] |
| Credential Scoping | Only declared env vars injected | sandbox.env.require: [...] |
| Resource Limits | CPU time, memory, file handles capped | sandbox.resources: {...} |
| Syscall Filtering | Dangerous system calls blocked | sandbox.syscalls: "restricted" |
Platform-Native Implementations
| Capability | Linux | macOS | Windows | Fallback (all platforms) |
|---|---|---|---|---|
| Process Isolation | bubblewrap (bwrap) + namespaces | App Sandbox (sandbox-exec) + Seatbelt profiles | Win32 AppContainer + Job Objects | Node.js child_process.fork() with restricted env |
| Filesystem | Mount namespaces + bind-mounts | Sandbox file access rules | Restricted Tokens + ACLs | chroot-like path validation in proxy |
| Network | Network namespace + iptables/nftables | Network extension / PF rules | Windows Firewall rules + Job Object net restrictions | Proxy-based outbound URL allowlist |
| Credential Scoping | Filtered env in namespace | Filtered env in sandbox | Filtered env in AppContainer | IPC proxy injects only declared vars |
| Resource Limits | cgroups v2 + ulimit | launchd resource limits | Job Object resource limits | Node.js --max-old-space-size + watchdog timer |
| Syscall Filtering | seccomp-bpf | Seatbelt syscall profiles | Restricted SID + Integrity Level | N/A (process boundary only) |
| Deep Isolation (optional) | gVisor (runsc) | Virtualization.framework | Windows Sandbox / WSL2 isolation | Docker container (if available) |
IPC Communication Model
Sandboxed plugins communicate with the host via a standardized IPC channel:
- Transport: Unix domain socket (Linux/macOS) or Named Pipe (Windows), with stdio JSON-RPC as universal fallback
- Protocol: JSON-RPC 2.0 over the transport
- SDK Proxy: The host process provides a proxy SDK that marshals API calls across the IPC boundary. Plugins see the same SDK interface; the proxy enforces capability checks before forwarding.
Tiered Preset System
| Preset | Target User | Process Isolation | FS Restriction | Network Restriction | Credential Scope | Resource Limits |
|---|---|---|---|---|---|---|
minimal |
Developers / self-hosted | None (current behavior) | Path validation only | None | Shared process.env | None |
standard (default) |
Regular users | Separate process per plugin | Read-only system dirs; write to plugin data dir | Outbound allowlist per plugin manifest | Only declared env vars | Memory 512MB, CPU 30s per operation |
strict |
Security-conscious users | Full platform-native sandbox | Minimal filesystem view | Strict allowlist + no raw socket | Credential vault with on-demand injection | Memory 256MB, CPU 10s, 100 file handles |
paranoid |
Enterprise / multi-tenant | Deep isolation (gVisor/VM) | Ephemeral filesystem per invocation | Network namespace + egress proxy | HSM-backed credential injection | Aggressive limits + watchdog termination |
Default: standard — provides meaningful protection without breaking most plugins. Users select their level via:
# ~/.config/openclaw/config.yaml
security:
sandbox_level: standard # minimal | standard | strict | paranoidPlugin Capability Manifest
Each plugin declares its requirements in manifest.yaml:
name: my-plugin
sandbox:
env:
require: [OPENAI_API_KEY, MY_PLUGIN_TOKEN]
fs:
read: ["./data/**", "/tmp/openclaw/**"]
write: ["./output/**"]
net:
allow: ["api.openai.com:443", "discord.com:443"]
tools:
allow: [read, write, message_send]
deny: [exec, shell]
commands:
register: ["/mycommand"]
http:
routes: ["/api/myplugin/*"]
auth: required # required | optional | none
resources:
max_memory: 256MB
max_cpu_time: 30sPlugins without a manifest run under the preset's default restrictions. Plugins requesting capabilities beyond the active preset level are either blocked or require explicit user approval.
Implementation Phases
| Phase | Action | Platforms | Effort | Blocks |
|---|---|---|---|---|
| Phase 1 | IPC proxy SDK layer — abstract plugin-host communication via JSON-RPC; plugins run as child processes with filtered env | All | High | Foundation for all phases |
| Phase 2 | Manifest schema + capability enforcement — parse manifest, enforce at proxy level | All | Medium | Requires Phase 1 |
| Phase 3a | Platform-native sandbox (Linux) — bwrap + namespaces + seccomp | Linux | Medium | Requires Phase 1 |
| Phase 3b | Platform-native sandbox (macOS) — App Sandbox + Seatbelt | macOS | Medium | Requires Phase 1 |
| Phase 3c | Platform-native sandbox (Windows) — AppContainer + Job Objects | Windows | Medium | Requires Phase 1 |
| Phase 4 | Tiered preset system + user-facing configuration | All | Low | Requires Phase 2 |
| Phase 5 | Optional deep isolation — gVisor (Linux), VM frameworks (macOS/Windows) | Per-platform | High | Optional |
Migration Strategy
- Ship Phase 1 with
minimalas default (backward compatible) - After Phase 2+3, switch default to
standard - Existing plugins auto-generate manifest from observed behavior during a "learning" period
- Grace period: plugins without manifest run with warnings, then restricted after N releases
Related Issues
Merged into this issue: Former CSD-001 (No Plugin Sandbox), Former CSD-002 (Cross-Plugin Credential Exposure)
Directly addressed ECOs: ECO-004, ECO-005, ECO-009, ECO-014, ECO-040, ECO-045, ECO-050
Architectural dependencies: CSD-003 (code signing works with manifest), CSD-004 (hook integrity benefits from process isolation), CSD-005 (command namespace isolation via manifest), CSD-006 (HTTP auth enforcement via manifest), CSD-008 (instruction isolation via sandbox context separation)