OpenClaw Exec Approvals: Run Host Commands Without Losing Control
Read from search, close with the playbook
If this post helped, here is the fastest path into the full operator setup.
Search posts do the first job. The preview, homepage, and full playbook show how the pieces fit together when you want the whole operating system.
The fastest way to make an agent useful is to let it run commands. The fastest way to make an agent expensive is to let it run the wrong command on the wrong machine.
OpenClaw's exec tool is intentionally powerful. It can run shell commands in the workspace, route work to the Gateway host, or target a paired node. It also supports foreground runs, background process sessions, pseudo-terminals for TTY-only CLIs, environment overrides, and per-call timeouts. That makes it the right tool for builds, deploys, diagnostics, repo maintenance, and local operator work.
But exec is not a read-only diagnostic surface. The current docs are explicit: shell commands can create, edit, or delete files wherever the selected host or sandbox filesystem permits. Disabling file-write tools does not turn shell execution into a safe viewer. If a command can mutate state, the operator has to treat it like a real production action.
That is where exec approvals matter. They are the guardrail that lets an operator keep command execution available without turning every agent run into full host trust.
What exec approvals actually protect
Exec approvals are enforced on the execution host. On the Gateway host, the openclaw process checks the policy before the command runs. On a node host, the node runner or macOS companion app enforces the policy locally. On macOS, the node host service forwards system.run to the macOS app over local IPC, and the app executes the command in UI context.
The important detail is composition. Exec approvals sit alongside tool policy and elevated mode. A command should run only when the broader OpenClaw tool policy allows exec, the selected host path is valid, the approval policy permits the command, and any required prompt is approved. In /elevated full mode, approvals are skipped, which is why that mode should stay a break-glass setting, not a daily default.
Approvals are not a separate per-user authorization boundary. Gateway-authenticated callers are trusted operators for that Gateway, and paired nodes extend that trusted operator capability onto the node host. The approval layer reduces accidental execution risk. It does not turn a trusted operator account into a multi-tenant permission system.
The three policy knobs that decide command flow
The host-local approval file lives at ~/.openclaw/exec-approvals.json. The same basic knobs appear in OpenClaw config and in the approval file, with the effective policy resolved conservatively. The docs describe the effective policy as the stricter of tools.exec.* and the approvals defaults when an approvals field is omitted.
{
"version": 1,
"defaults": {
"security": "deny",
"ask": "on-miss",
"askFallback": "deny",
"autoAllowSkills": false
},
"agents": {
"main": {
"security": "allowlist",
"ask": "on-miss",
"askFallback": "deny",
"autoAllowSkills": false,
"allowlist": [
{
"pattern": "/opt/homebrew/bin/rg"
}
]
}
}
} There are three settings I care about when operating a real workspace:
security="deny"blocks host exec requests.security="allowlist"allows only commands whose resolved executable path or allowed command name matches policy.security="full"allows everything and is equivalent to no approval gate for that layer.
The ask setting controls prompts. off never prompts. on-miss prompts only when the allowlist does not match. always prompts on every command, and durable allow-always trust does not suppress prompts when the effective mode is always.
The third setting, askFallback, is the one people forget. If a prompt is required but the companion UI is unavailable, OpenClaw needs a deterministic answer. The default fallback is deny. That is what I want for production: if nobody can review the command, the command should not run.
Trying to make agents useful without handing them your whole machine?
ClawKit gives you the operating patterns for safe command lanes, memory, tool policy, and production recovery. Get ClawKit for $9.99.
Use allowlists for tools, not for vibes
The allowlist is per agent. That matters if you run separate agents for personal ops, product work, customer channels, or marketing automation. A path trusted for one agent should not silently become trusted for every agent.
The current public docs allow resolved binary path globs and bare command-name globs. Path globs are the safer habit when a command matters. Trusting /opt/homebrew/bin/rg is clearer than trusting any executable named rg that happens to appear in a manipulated PATH. Older local docs also emphasize resolved binary paths and case-insensitive glob behavior, so the conservative posture is still the same: approve the executable you actually mean.
Do not allowlist an interpreter and call the problem solved. python3, node, bash, sh, zsh, ruby, and similar runtimes can evaluate code, run loaders, or execute subcommands. If you need them, approve them deliberately and keep inline eval hardening on.
{
tools: {
exec: {
host: "auto",
security: "allowlist",
ask: "on-miss",
strictInlineEval: true,
safeBins: ["cut", "uniq", "head", "tail", "tr", "wc"]
}
}
} tools.exec.strictInlineEval=true makes inline eval forms approval-only even when the interpreter binary itself is allowlisted. The docs list forms such as python -c, node -e, node --eval, ruby -e, perl -e, php -r, lua -e, and osascript -e. In strict mode, those commands still require explicit approval, and allow-always does not automatically persist new allowlist entries for them.
Safe bins are narrow stream filters
OpenClaw also has tools.exec.safeBins, but the name is easy to overread. Safe bins are not a second general allowlist. They are a small stdin-only fast path for commands such as cut, uniq, head, tail, tr, and wc.
The documented behavior is intentionally strict. Safe bins reject positional file arguments and path-like tokens, force argv tokens to literal text for stdin-only segments, use explicit per-binary flag policies, and resolve only from trusted directories. The default trusted directories are /bin and /usr/bin. PATH entries are not automatically trusted.
That makes safe bins useful for low-risk stream transforms inside pipelines. It does not make jq, grep, sort, or an interpreter safe by default. The docs call out denied flags for file-oriented behavior, including recursive grep flags, jq -f, sort -o, and wc --files0-from. If a command reads files, evaluates code, expands scripts, or has broad side effects, put it behind an explicit allowlist and prompt policy.
Host selection is part of the safety model
The exec tool can run on auto, sandbox, gateway, or node. Current docs describe auto as sandbox when a sandbox runtime is active and Gateway otherwise. It is not a hostname selector and not a free override. Host-like values are rejected before the command runs.
That distinction prevents a common operator mistake. Choosing auto decides where execution routes. Choosing no-approval host exec decides how approval works. They are not the same policy. If you want reliable host routing, set the host intentionally. If you want approval-gated host execution, tighten both tools.exec.* and the host-local approvals file.
For node execution, the docs are also direct: node requires a paired node, and if multiple nodes are available you should bind the target with exec.node or tools.exec.node. The Control UI has an exec node binding panel, and the CLI path looks like this:
openclaw config get agents.list
openclaw config set 'agents.list[0].tools.exec.node' "mac-ops-node" Host execution rejects env.PATH and loader override variables such as LD_* and DYLD_*. That is a good example of a small implementation detail with real security value: a caller should not be able to get an approved command name and then swap the binary through environment injection.
Use session overrides sparingly
Operators can use /exec to set per-session defaults for host, security, ask, and node. Send /exec by itself to see the current values. A directive like this updates session state only; it does not write persistent config:
/exec host=auto security=allowlist ask=on-miss node=mac-1 The directive is honored only for authorized senders through channel allowlists, pairing, and access-group checks. That is useful for a human operator moving one conversation into a safer host-exec lane. It is not a substitute for persistent policy. If the system should never run shell commands, deny exec through tool policy.
Elevated mode is different. /elevated on or /elevated ask lets a sandboxed agent run outside the sandbox while keeping approvals. /elevated full leaves the sandbox and skips approvals. /elevated off returns to sandbox-confined execution. Elevated only changes behavior when the agent is sandboxed; an unsandboxed agent is already running on the host.
My rule is simple: use /exec for temporary routing and approval posture; use /elevated full only when the human operator is actively supervising a specific break-glass task.
A practical policy for revenue work
If an agent is going to build, deploy, index, or update customer-facing content, I want it to have enough power to finish the job and enough friction to stop the dangerous cases. A practical baseline looks like this:
- Keep normal work in
host=autoor sandboxed execution when the sandbox is available. - Use
allowlistplusask="on-miss"for Gateway or node host execution. - Set
askFallback="deny"so missing UI does not become silent approval. - Allowlist exact executables or narrow path globs, not broad interpreter trust.
- Turn on
strictInlineEvalbefore approving interpreter binaries. - Reserve
safeBinsfor stdin-only stream filters. - Use node binding when physical-device or macOS-context work must run on a specific node.
- Leave
/elevated fullfor supervised incidents and one-off recovery.
The goal is not to make agents timid. The goal is to make command authority understandable. When a command runs, you should know which host it ran on, why it was allowed, whether a human prompt was required, and what boundary would have stopped it if the request drifted.
That is the difference between an agent that can safely operate a business workflow and an agent that just has a shell. The shell gets demos. The approval model gets sleep.
Want the complete guide? Get ClawKit — $9.99