Skip to content

Commit 9f413ac

Browse files
authored
fix: expand unsafe host env denylist (#91618)
* fix: expand unsafe host env denylist * test: annotate host env security fixtures * test: align opengrep fixture suppressions * test: keep opengrep suppressions inline * test: avoid opengrep fixture call patterns
1 parent 98d5c46 commit 9f413ac

8 files changed

Lines changed: 252 additions & 201 deletions

File tree

apps/macos/Sources/OpenClaw/HostEnvSecurityPolicy.generated.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ enum HostEnvSecurityPolicy {
2828
"AWS_SESSION_TOKEN",
2929
"AZURE_CLIENT_ID",
3030
"AZURE_CLIENT_SECRET",
31+
"BASHOPTS",
3132
"BASH_ENV",
3233
"BROWSER",
3334
"BUNDLE_GEMFILE",
@@ -70,6 +71,7 @@ enum HostEnvSecurityPolicy {
7071
"ERL_ZFLAGS",
7172
"EXINIT",
7273
"FCEDIT",
74+
"FPATH",
7375
"GCONV_PATH",
7476
"GEM_HOME",
7577
"GEM_PATH",
@@ -116,6 +118,7 @@ enum HostEnvSecurityPolicy {
116118
"JAVA_TOOL_OPTIONS",
117119
"JDK_JAVA_OPTIONS",
118120
"JULIA_EDITOR",
121+
"KSH_ENV",
119122
"LDFLAGS",
120123
"LESSCLOSE",
121124
"LESSOPEN",
@@ -183,6 +186,7 @@ enum HostEnvSecurityPolicy {
183186
"SUDO_EDITOR",
184187
"SVN_EDITOR",
185188
"SVN_SSH",
189+
"TCLLIBPATH",
186190
"TF_CLI_CONFIG_FILE",
187191
"TF_PLUGIN_CACHE_DIR",
188192
"UV_DEFAULT_INDEX",
@@ -207,6 +211,7 @@ enum HostEnvSecurityPolicy {
207211

208212
static let blockedKeys: Set<String> = [
209213
"ANT_OPTS",
214+
"BASHOPTS",
210215
"BASH_ENV",
211216
"BROWSER",
212217
"BZR_EDITOR",
@@ -232,6 +237,7 @@ enum HostEnvSecurityPolicy {
232237
"ERL_FLAGS",
233238
"ERL_ZFLAGS",
234239
"EXINIT",
240+
"FPATH",
235241
"GCONV_PATH",
236242
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
237243
"GIT_COMMON_DIR",
@@ -260,6 +266,7 @@ enum HostEnvSecurityPolicy {
260266
"JAVA_TOOL_OPTIONS",
261267
"JDK_JAVA_OPTIONS",
262268
"JULIA_EDITOR",
269+
"KSH_ENV",
263270
"LUA_INIT",
264271
"LUA_INIT_5_1",
265272
"LUA_INIT_5_2",
@@ -297,6 +304,7 @@ enum HostEnvSecurityPolicy {
297304
"SUDO_ASKPASS",
298305
"SVN_EDITOR",
299306
"SVN_SSH",
307+
"TCLLIBPATH",
300308
"VAGRANT_VAGRANTFILE",
301309
"VIMINIT",
302310
"_JAVA_OPTIONS"

docs/cli/mcp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ Launches a local child process and communicates over stdin/stdout.
673673
<Warning>
674674
**Stdio env safety filter**
675675

676-
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`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `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, enable a debugger, or redirect runtime output against the stdio process. Ordinary credential, proxy, and server-specific env vars (`GITHUB_TOKEN`, `HTTP_PROXY`, custom `*_API_KEY`, etc.) are unaffected.
676+
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 `BASHOPTS`, `FPATH`, `KSH_ENV`, `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHONSTARTUP`, `PYTHONPATH`, `PERL5OPT`, `RUBYOPT`, `SHELLOPTS`, `PS4`, `TCLLIBPATH`, and similar runtime-control variables. Startup rejects these with a configuration error so they cannot inject an implicit prelude, swap the interpreter, enable a debugger, or redirect runtime output against the stdio process. Ordinary credential, proxy, and server-specific env vars (`GITHUB_TOKEN`, `HTTP_PROXY`, custom `*_API_KEY`, etc.) are unaffected.
677677

678678
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`.
679679
</Warning>

docs/nodes/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ Notes:
381381
- For allow-always decisions in allowlist mode, known dispatch wrappers (`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist inner executable paths instead of wrapper paths. If unwrapping is not safe, no allowlist entry is persisted automatically.
382382
- On Windows node hosts in allowlist mode, shell-wrapper runs via `cmd.exe /c` require approval (allowlist entry alone does not auto-allow the wrapper form).
383383
- `system.notify` supports `--priority <passive|active|timeSensitive>` and `--delivery <system|overlay|auto>`.
384-
- Node hosts ignore `PATH` overrides and strip dangerous startup/shell keys (`DYLD_*`, `LD_*`, `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`). If you need extra PATH entries, configure the node host service environment (or install tools in standard locations) instead of passing `PATH` via `--env`.
384+
- Node hosts ignore `PATH` overrides and strip dangerous startup/shell keys (`DYLD_*`, `LD_*`, `BASHOPTS`, `FPATH`, `KSH_ENV`, `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`, `TCLLIBPATH`). If you need extra PATH entries, configure the node host service environment (or install tools in standard locations) instead of passing `PATH` via `--env`.
385385
- On macOS node mode, `system.run` is gated by exec approvals in the macOS app (Settings → Exec approvals).
386386
Ask/allowlist/full behave the same as the headless node host; denied prompts return `SYSTEM_RUN_DENIED`.
387387
- On headless node host, `system.run` is gated by exec approvals (`~/.openclaw/exec-approvals.json`).

docs/platforms/macos.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Notes:
107107
- `allowlist` entries are glob patterns for resolved binary paths, or bare command names for PATH-invoked commands.
108108
- Raw shell command text that contains shell control or expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is treated as an allowlist miss and requires explicit approval (or allowlisting the shell binary).
109109
- Choosing "Always Allow" in the prompt adds that command to the allowlist.
110-
- `system.run` environment overrides are filtered (drops `PATH`, `DYLD_*`, `LD_*`, `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`) and then merged with the app's environment.
110+
- `system.run` environment overrides are filtered (drops `PATH`, `DYLD_*`, `LD_*`, `BASHOPTS`, `FPATH`, `KSH_ENV`, `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`, `TCLLIBPATH`) and then merged with the app's environment.
111111
- For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped environment overrides are reduced to a small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`).
112112
- For allow-always decisions in allowlist mode, known dispatch wrappers (`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist inner executable paths instead of wrapper paths. If unwrapping is not safe, no allowlist entry is persisted automatically.
113113

src/infra/host-env-security-policy.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
"PERL5OPT",
1313
"RUBYLIB",
1414
"RUBYOPT",
15+
"BASHOPTS",
1516
"BASH_ENV",
1617
"ENV",
18+
"KSH_ENV",
1719
"BROWSER",
1820
"GIT_EDITOR",
1921
"GIT_EXTERNAL_DIFF",
@@ -50,6 +52,7 @@
5052
"PYTHONBREAKPOINT",
5153
"DOTNET_STARTUP_HOOKS",
5254
"DOTNET_ADDITIONAL_DEPS",
55+
"FPATH",
5356
"GLIBC_TUNABLES",
5457
"MAVEN_OPTS",
5558
"MAKEFLAGS",
@@ -93,6 +96,7 @@
9396
"R_PROFILE",
9497
"R_ENVIRON_USER",
9598
"R_PROFILE_USER",
99+
"TCLLIBPATH",
96100
"HOSTALIASES"
97101
],
98102
"blockedOverrideOnlyKeys": [

src/infra/host-env-security.reported-baseline.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"generatedAt": "2026-04-10",
44
"reportedDangerousEverywhereKeys": [
55
"ANT_OPTS",
6+
"BASHOPTS",
67
"BASH_ENV",
78
"BROWSER",
89
"BZR_EDITOR",
@@ -28,6 +29,7 @@
2829
"ERL_FLAGS",
2930
"ERL_ZFLAGS",
3031
"EXINIT",
32+
"FPATH",
3133
"GCONV_PATH",
3234
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
3335
"GIT_COMMON_DIR",
@@ -56,6 +58,7 @@
5658
"JAVA_TOOL_OPTIONS",
5759
"JDK_JAVA_OPTIONS",
5860
"JULIA_EDITOR",
61+
"KSH_ENV",
5962
"LUA_INIT",
6063
"LUA_INIT_5_1",
6164
"LUA_INIT_5_2",
@@ -93,6 +96,7 @@
9396
"SUDO_ASKPASS",
9497
"SVN_EDITOR",
9598
"SVN_SSH",
99+
"TCLLIBPATH",
96100
"VAGRANT_VAGRANTFILE",
97101
"VIMINIT",
98102
"_JAVA_OPTIONS"
@@ -248,5 +252,5 @@
248252
"YARN_RC_FILENAME",
249253
"ZDOTDIR"
250254
],
251-
"expectedTotalReportedEntries": 243
255+
"expectedTotalReportedEntries": 247
252256
}

src/infra/host-env-security.reported-baseline.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ describe("host env reported baseline coverage", () => {
9292
baseline.reportedDangerousEverywhereKeys.length +
9393
baseline.reportedDangerousOverrideOnlyKeys.length,
9494
).toBe(baseline.expectedTotalReportedEntries);
95-
expect(baseline.expectedTotalReportedEntries).toBe(243);
95+
expect(baseline.expectedTotalReportedEntries).toBe(247);
9696
expect(sortUniqueUpper(baseline.reportedDangerousEverywhereKeys)).toEqual(
9797
baseline.reportedDangerousEverywhereKeys,
9898
);

0 commit comments

Comments
 (0)