From b4a59be9b6f238aa35d00190ac800ca91f12c376 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 21 Apr 2026 13:21:34 -0700 Subject: [PATCH] docs: document stdio env filter, enforceOwnerForCommands, OPENCLAW_* .env blocking --- docs/cli/mcp.md | 6 ++++++ docs/gateway/security/index.md | 12 +++++++++++- docs/tools/slash-commands.md | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/cli/mcp.md b/docs/cli/mcp.md index c2cbee48603..02e42e6fae2 100644 --- a/docs/cli/mcp.md +++ b/docs/cli/mcp.md @@ -428,6 +428,12 @@ Launches a local child process and communicates over stdin/stdout. | `env` | Extra environment variables | | `cwd` / `workingDirectory` | Working directory for the process | +#### Stdio env safety filter + +OpenClaw rejects interpreter-startup env keys that can alter how a stdio MCP server starts up before the first RPC, even if they appear in a server's `env` block. Blocked keys include `NODE_OPTIONS`, `PYTHONSTARTUP`, `PYTHONPATH`, `PERL5OPT`, `RUBYOPT`, `SHELLOPTS`, `PS4`, and similar runtime-control variables. Startup rejects these with a configuration error so they cannot inject an implicit prelude, swap the interpreter, or enable a debugger against the stdio process. Ordinary credential, proxy, and server-specific env vars (`GITHUB_TOKEN`, `HTTP_PROXY`, custom `*_API_KEY`, etc.) are unaffected. + +If your MCP server genuinely needs one of the blocked variables, set it on the gateway host process instead of under the stdio server's `env`. + ### SSE / HTTP transport Connects to a remote MCP server over HTTP Server-Sent Events. diff --git a/docs/gateway/security/index.md b/docs/gateway/security/index.md index 4b911d44b4d..91f97fd5d97 100644 --- a/docs/gateway/security/index.md +++ b/docs/gateway/security/index.md @@ -1024,7 +1024,17 @@ Hardening tips: - Use full-disk encryption on the gateway host. - Prefer a dedicated OS user account for the Gateway if the host is shared. -### 0.8) Logs + transcripts (redaction + retention) +### 0.8) Workspace `.env` files + +OpenClaw loads workspace-local `.env` files for agents and tools, but never lets those files silently override gateway runtime controls. + +- Any key that starts with `OPENCLAW_*` is blocked from untrusted workspace `.env` files. +- The block is fail-closed: a new runtime-control variable added in a future release cannot be inherited from a checked-in or attacker-supplied `.env`; the key is ignored and the gateway keeps its own value. +- Trusted process/OS environment variables (the gateway's own shell, launchd/systemd unit, app bundle) still apply — this only constrains `.env` file loading. + +Why: workspace `.env` files frequently live next to agent code, get committed by accident, or get written by tools. Blocking the whole `OPENCLAW_*` prefix means adding a new `OPENCLAW_*` flag later can never regress into silent inheritance from workspace state. + +### 0.9) Logs + transcripts (redaction + retention) Logs and transcripts can leak sensitive info even when access controls are correct: diff --git a/docs/tools/slash-commands.md b/docs/tools/slash-commands.md index 885e1e86fef..4f3af21d73e 100644 --- a/docs/tools/slash-commands.md +++ b/docs/tools/slash-commands.md @@ -69,6 +69,7 @@ They run immediately, are stripped before the model sees the message, and the re - `commands.debug` (default `false`) enables `/debug` (runtime-only overrides). - `commands.restart` (default `true`) enables `/restart` plus gateway restart tool actions. - `commands.ownerAllowFrom` (optional) sets the explicit owner allowlist for owner-only command/tool surfaces. This is separate from `commands.allowFrom`. +- Per-channel `channels..commands.enforceOwnerForCommands` (optional, default `false`) makes owner-only commands require **owner identity** to run on that surface. When `true`, the sender must either match a resolved owner candidate (for example an entry in `commands.ownerAllowFrom` or provider-native owner metadata) or hold internal `operator.admin` scope on an internal message channel. A wildcard entry in channel `allowFrom`, or an empty/unresolved owner-candidate list, is **not** sufficient — owner-only commands fail closed on that channel. Leave this off if you want owner-only commands gated only by `ownerAllowFrom` and the standard command allowlists. - `commands.ownerDisplay` controls how owner ids appear in the system prompt: `raw` or `hash`. - `commands.ownerDisplaySecret` optionally sets the HMAC secret used when `commands.ownerDisplay="hash"`. - `commands.allowFrom` (optional) sets a per-provider allowlist for command authorization. When configured, it is the