fix(security): harden exec approval boundaries

This commit is contained in:
Peter Steinberger
2026-03-22 09:35:16 -07:00
parent e99d44525a
commit a94ec3b79b
29 changed files with 835 additions and 67 deletions

View File

@@ -107,6 +107,25 @@ If a prompt is required but no UI is reachable, fallback decides:
- **allowlist**: allow only if allowlist matches.
- **full**: allow.
### Inline interpreter eval hardening (`tools.exec.strictInlineEval`)
When `tools.exec.strictInlineEval=true`, OpenClaw treats inline code-eval forms as approval-only even if the interpreter binary itself is allowlisted.
Examples:
- `python -c`
- `node -e`, `node --eval`, `node -p`
- `ruby -e`
- `perl -e`, `perl -E`
- `php -r`
- `lua -e`
- `osascript -e`
This is defense-in-depth for interpreter loaders that do not map cleanly to one stable file operand. In strict mode:
- these commands still need explicit approval;
- `allow-always` does not persist new allowlist entries for them automatically.
## Allowlist (per agent)
Allowlists are **per agent**. If multiple agents exist, switch which agent youre
@@ -194,6 +213,7 @@ For allow-always decisions in allowlist mode, known dispatch wrappers
paths. Shell multiplexers (`busybox`, `toybox`) are also unwrapped for shell applets (`sh`, `ash`,
etc.) so inner executables are persisted instead of multiplexer binaries. If a wrapper or
multiplexer cannot be safely unwrapped, no allowlist entry is persisted automatically.
If you allowlist interpreters like `python3` or `node`, prefer `tools.exec.strictInlineEval=true` so inline eval still requires an explicit approval.
Default safe bins: `jq`, `cut`, `uniq`, `head`, `tail`, `tr`, `wc`.

View File

@@ -56,6 +56,7 @@ Notes:
- `tools.exec.security` (default: `deny` for sandbox, `allowlist` for gateway + node when unset)
- `tools.exec.ask` (default: `on-miss`)
- `tools.exec.node` (default: unset)
- `tools.exec.strictInlineEval` (default: false): when true, inline interpreter eval forms such as `python -c`, `node -e`, `ruby -e`, `perl -e`, `php -r`, `lua -e`, and `osascript -e` always require explicit approval and are never persisted by `allow-always`.
- `tools.exec.pathPrepend`: list of directories to prepend to `PATH` for exec runs (gateway + sandbox only).
- `tools.exec.safeBins`: stdin-only safe binaries that can run without explicit allowlist entries. For behavior details, see [Safe bins](/tools/exec-approvals#safe-bins-stdin-only).
- `tools.exec.safeBinTrustedDirs`: additional explicit directories trusted for `safeBins` path checks. `PATH` entries are never auto-trusted. Built-in defaults are `/bin` and `/usr/bin`.
@@ -143,6 +144,7 @@ Use the two controls for different jobs:
Do not treat `safeBins` as a generic allowlist, and do not add interpreter/runtime binaries (for example `python3`, `node`, `ruby`, `bash`). If you need those, use explicit allowlist entries and keep approval prompts enabled.
`openclaw security audit` warns when interpreter/runtime `safeBins` entries are missing explicit profiles, and `openclaw doctor --fix` can scaffold missing custom `safeBinProfiles` entries.
If you explicitly allowlist interpreters, enable `tools.exec.strictInlineEval` so inline code-eval forms still require a fresh approval.
For full policy details and examples, see [Exec approvals](/tools/exec-approvals#safe-bins-stdin-only) and [Safe bins versus allowlist](/tools/exec-approvals#safe-bins-versus-allowlist).