Exec approvals: guardrails for host commands in Neura
Explains how exec approvals act as a guardrail between a companion app and a node host, requiring policy, allowlist, and optional user approval for command execution. For developers and operators configuring host exec security.
Read this when
- Configuring exec approvals or allowlists
- Implementing exec approval UX in the macOS app
- Reviewing sandbox-escape prompts and their implications
Exec approvals act as a guardrail between a companion app and a node host, allowing a sandboxed agent to issue commands on a real machine (gateway or node). A command executes only when policy, an allowlist, and optional user approval all align. These approvals operate on top of tool policy and elevated gating (elevated full bypasses them).
For a mode-first breakdown of deny, allowlist, ask, auto, full, Codex Guardian mapping, and ACPX harness permissions, refer to Permission modes.
Note
The effective policy is the more restrictive of
tools.exec.*and the approvals defaults. Approvals can only tighten security or prompting derived from configuration, never relax them. When an approvals field is omitted, thetools.execvalue applies. Host exec also uses the local approvals state on that machine. A host-localask: "always"in the execution host approvals file keeps prompting, even if the session or config defaults requestask: "on-miss".
Where it applies
Exec approvals are applied locally on the execution host:
- Gateway host -> the
openclawprocess on the gateway machine. - Node host -> the node runner (macOS companion app or headless node host).
Trust model
- Callers authenticated by the Gateway are considered trusted operators for that Gateway.
- Paired nodes extend that trusted operator capability to the node host.
- Approvals lower the risk of accidental execution but do not serve as a per-user authentication boundary or a filesystem read-only policy.
- Once approved, a command can modify files based on the selected host or sandbox filesystem permissions.
- Approved node-host runs bind the canonical execution context: the current working directory, exact argv, environment bindings when present, and the pinned executable path when applicable.
- For shell scripts and direct interpreter or runtime file invocations, OpenClaw also attempts to bind one specific local file operand. If that file changes after approval but before execution, the run is denied to prevent executing drifted content.
- File binding is best-effort and does not fully model every interpreter or runtime loader path. If exactly one concrete local file cannot be identified, OpenClaw refuses to create an approval-backed run rather than pretending full coverage.
macOS split
- The node host service forwards
system.runto the macOS app over local IPC. - The macOS app enforces approvals and runs the command within the UI context.
Inspecting the effective policy
| Command | What it shows |
|---|---|
openclaw approvals get / --gateway / --node <id|name|ip> | The requested policy, host policy sources, and the effective result. |
openclaw exec-policy show | A merged view from the local machine. |
openclaw exec-policy set / preset | Sync the local requested policy with the local host approvals file in a single step. |
Note
Per-session
/execoverrides are excluded. Run/execin the relevant session to check its current defaults. See session overrides.
For the full CLI reference, including flags, JSON output, and allowlist add/remove operations, see Approvals CLI.
When a local scope requests host=node, exec-policy show reports that scope as node-managed at runtime instead of treating the local approvals file as the source of truth.
If the companion app UI is unavailable, any request that would normally trigger a prompt is resolved by the ask fallback (default: deny).
Tip
Native chat approval clients can seed channel-specific affordances on the pending approval message. Matrix seeds reaction shortcuts (
✅allow once,♾️allow always,❌deny) while still leaving/approve ...in the message as a fallback.
Settings and storage
Approvals are stored in a local JSON file on the execution host. When OPENCLAW_STATE_DIR is set, the file follows that state directory; otherwise, it uses the default OpenClaw state directory:
$OPENCLAW_STATE_DIR/exec-approvals.json
# otherwise
~/.openclaw/exec-approvals.json
The default approval socket follows the same root: $OPENCLAW_STATE_DIR/exec-approvals.sock, or ~/.openclaw/exec-approvals.sock when the variable is unset.
State directories are independent trust scopes. When OPENCLAW_STATE_DIR points elsewhere, OpenClaw never imports or archives ~/.openclaw/exec-approvals.json; configure approvals separately for the custom state directory. Doctor also imports legacy plugin-binding-approvals.json only when it belongs to the active state directory.
Example schema:
{
"version": 1,
"socket": {
"path": "~/.openclaw/exec-approvals.sock",
"token": "base64url-token"
},
"defaults": {
"security": "deny",
"ask": "on-miss",
"askFallback": "deny",
"autoAllowSkills": false
},
"agents": {
"main": {
"security": "allowlist",
"ask": "on-miss",
"askFallback": "deny",
"autoAllowSkills": true,
"allowlist": [
{
"id": "B0C8C0B3-2C2D-4F8A-9A3C-5A4B3C2D1E0F",
"pattern": "~/Projects/**/bin/rg",
"argPattern": "sha256:argv:...",
"source": "allow-always",
"lastUsedAt": 1737150000000,
"lastResolvedPath": "/Users/user/Projects/.../bin/rg"
},
{
"pattern": "~/Projects/**/bin/git"
}
]
}
}
}
Policy knobs
tools.exec.mode
tools.exec.mode is the preferred normalized policy surface for host exec:
| Value | Behavior |
|---|---|
deny | Block host exec. |
allowlist | Run only allowlisted commands without prompting. |
ask | Apply the allowlist policy and ask on misses. |
auto | Apply the allowlist policy, run deterministic matches directly, and send approval misses through OpenClaw's native auto reviewer before falling back to a human approval route. |
full | Run host exec without approval prompts. |
Doctor migrates the retired persisted tools.exec.security / tools.exec.ask pair to tools.exec.mode.
exec.security
security(deny" | "allowlist" | "full),denystops all host exec requests.allowlistpermits only commands on the allowlist.fullgrants unrestricted access (same as elevated). The default isfullfor gateway or node hosts; asandboxhost usesdenyas its default.
exec.ask
ask(off" | "on-miss" | "always), Determines the ask policy for host exec. This controls how approval prompts behave by default fromtools.exec.askand the host approvals defaults. Defaults tooff. The per-callasktool parameter (see Exec tool) can only make that baseline stricter, and channel-origin model calls ignore it when the effective host ask isoff.offmeans no prompt ever appears.on-missprompts only when the allowlist does not match.alwaysprompts for every command. When the effective ask mode isalways,allow-alwaysdurable trust does not suppress prompts.
askFallback
askFallback(deny" | "allowlist" | "full), Defines what happens when a prompt is needed but no UI can be reached, or the prompt times out. When omitted, the default isdeny.denyblocks the request.allowlistallows it only if the allowlist matches.fullallows it unconditionally.
tools.exec.strictInlineEval
strictInlineEval(boolean), Whentrue, inline code-eval forms require approval even if the interpreter binary itself is on the allowlist. This provides defense-in-depth for interpreter loaders that do not cleanly map to a single stable file operand.
Examples caught by strict mode: python -c, node -e/--eval/-p,
ruby -e, perl -e/-E, php -r, lua -e, osascript -e (also awk,
sed, make, find -exec, and xargs inline forms).
In strict mode these commands need reviewer or explicit approval. With
tools.exec.mode: "auto", the reviewer can grant one low-risk execution when
the command has an enforceable plan; otherwise OpenClaw asks a human.
Codex app-server command approvals that reach the reviewer fallback ask a
human because their approval requests do not expose an enforceable resolved
executable.
allow-always does not persist new allowlist entries for inline-eval commands.
tools.exec.commandHighlighting
commandHighlighting(boolean, default: false), Display only: when turned on, OpenClaw may attach parser-derived command spans so Web approval prompts can highlight command tokens. Does not affectsecurity,ask, allowlist matching, strict inline-eval behavior, approval forwarding, or command execution.
Set globally under tools.exec.commandHighlighting or per agent under
agents.entries.*.tools.exec.commandHighlighting.
YOLO mode (no-approval)
To run host exec without approval prompts, open both policy layers:
the requested exec policy in OpenClaw config (tools.exec.*) and
the host-local approvals policy in the execution host approvals file.
If askFallback is omitted it defaults to deny. Explicitly set host askFallback
to full when a no-UI approval prompt should fall back to allow.
| Layer | YOLO setting |
|---|---|
tools.exec.mode | full on gateway/node |
Host askFallback | full |
Warning
Key differences:
tools.exec.host=autodetermines where execution occurs: in a sandbox when possible, otherwise through the gateway.- YOLO dictates how host-level execution gets approved: using
security=fullin combination withask=off.- YOLO does not introduce an extra heuristic command-obfuscation approval step or a script-preflight rejection mechanism on top of whatever host exec policy is already configured.
autodoes not allow gateway routing to be freely overridden from within a sandboxed session. A per-callhost=noderequest is permitted fromauto;host=gatewayis only permitted fromautowhen no sandbox runtime is currently active. For a stable non-auto default, either configuretools.exec.hostor explicitly use/exec host=....
CLI-backed providers that expose their own noninteractive permission mode
can adhere to this policy. Claude CLI adds
--permission-mode bypassPermissions when OpenClaw's effective exec
policy is YOLO. For OpenClaw-managed Claude live sessions, OpenClaw's
effective exec policy takes precedence over Claude's native permission mode:
YOLO normalizes live launches to --permission-mode bypassPermissions, and
a restrictive effective exec policy normalizes live launches to
--permission-mode default, even if the raw Claude backend arguments specify a different
mode.
For a more conservative setup, restrict OpenClaw's exec policy back to
allowlist / on-miss or deny.
Persistent gateway-host "never prompt" setup
Set the requested config policy
openclaw config set tools.exec.host gateway
openclaw config set tools.exec.mode full
openclaw gateway restart
Match the host approvals file
openclaw approvals set --stdin <<'EOF'
{
version: 1,
defaults: {
security: "full",
ask: "off",
askFallback: "full"
}
}
EOF
Local shortcut
openclaw exec-policy preset yolo
Updates both the local tools.exec.host/security/ask and the local approvals
file defaults (which includes askFallback: "full"). This is intentionally
limited to the local machine. To update gateway-host or node-host approvals remotely, use
openclaw approvals set --gateway or openclaw approvals set --node <id|name|ip>.
Other built-in presets include cautious (host=gateway, security=allowlist,
ask=on-miss, askFallback=deny) and deny-all (host=gateway,
security=deny, ask=off, askFallback=deny). Apply them in the same manner:
openclaw exec-policy preset cautious.
To configure individual fields rather than an entire preset, use
openclaw exec-policy set --host <auto|sandbox|gateway|node> --security <deny|allowlist|full> --ask <off|on-miss|always> --ask-fallback <deny|allowlist|full> with any subset of those flags.
Node host
Apply the same approvals file on the node instead:
openclaw approvals set --node <id|name|ip> --stdin <<'EOF'
{
version: 1,
defaults: {
security: "full",
ask: "off",
askFallback: "full"
}
}
EOF
Note
Local-only constraints:
openclaw exec-policydoes not sync node approvals.openclaw exec-policy set --host nodeis not accepted.- Node exec approvals are retrieved from the node at runtime, so any node-targeted updates must use
openclaw approvals --node ....
Session-only shortcut
/exec security=full ask=offaffects only the current session./elevated fullacts as a break-glass shortcut that bypasses exec approvals only when both the requested policy and the host approvals file resolve tosecurity: "full"andask: "off". A more restrictive host file, such asask: "always", still triggers a prompt.
If the host approvals file remains more restrictive than the configuration, the stricter host policy still takes effect.
Allowlist (per agent)
Allowlists apply per agent. When multiple agents exist, switch which agent you are editing within the macOS app. Patterns use glob matching.
Patterns can be either resolved binary path globs or bare command-name globs. Bare names only match commands invoked via PATH, so rg can match /opt/homebrew/bin/rg when the command is rg, but not ./rg or /tmp/rg. To trust a specific binary location, use a path glob.
On load, legacy agents.default entries are converted to agents.main. Shell chains like echo ok && pwd still require each top-level segment to comply with allowlist rules.
Examples:
rg~/Projects/**/bin/peekaboo~/.local/bin/*/opt/homebrew/bin/rg
Restricting arguments with argPattern
Add argPattern when an allowlist entry should match both a binary and a specific argument pattern. OpenClaw applies ECMAScript (JavaScript) regular expression semantics on all hosts, evaluating the expression against the parsed command arguments while excluding the executable token (argv[0]). For manually written entries, arguments are joined with a single space, so anchor the pattern when you require an exact match.
{
"version": 1,
"agents": {
"main": {
"allowlist": [
{
"pattern": "python3",
"argPattern": "^safe\\.py$"
}
]
}
}
}
That entry permits python3 safe.py; python3 other.py is an allowlist miss. If a path-only entry for the same binary also exists, unmatched arguments can still fall back to that path-only entry. Omit the path-only entry when the goal is to restrict the binary to the declared arguments.
Entries created by approval flows use an internal separator format for exact argv matching. Prefer the UI or approval flow to regenerate those entries instead of manually editing the encoded value. If OpenClaw cannot parse argv for a command segment, entries with argPattern do not match.
Generated allow-always entries are argv-bound. New generated entries include argPattern; older generated path-only entries are ignored and require a fresh approval. For a manual path-only rule, omit both source and argPattern.
Each allowlist entry supports:
| Field | Meaning |
|---|---|
pattern | Resolved binary path glob or bare command-name glob |
argPattern | ECMAScript argv regex or generated exact-argv hash; omitted is path-only |
id | Stable opaque ID; generated as a UUID when absent |
source | Generated entry source, such as allow-always; omit for manual entries |
commandText | Legacy plaintext input; discarded during load |
lastUsedAt | Last-used timestamp |
lastUsedCommand | Last command that matched; omitted for generated hashed argv entries |
lastResolvedPath | Last resolved binary path |
Auto-allow skill CLIs
When Auto-allow skill CLIs (autoAllowSkills) is enabled, executables referenced by known skills are treated as allowlisted on nodes (macOS node or headless node host). This uses skills.bins over the Gateway RPC to retrieve the skill bin list. Disable this if you want strict manual allowlists.
Warning
- This is an implicit convenience allowlist, separate from manual path allowlist entries.
- It is intended for trusted operator environments where Gateway and node are in the same trust boundary.
- If you require strict explicit trust, keep
autoAllowSkills: falseand use manual path allowlist entries only.
Safe bins and approval forwarding
For safe bins (the stdin-only fast-path), interpreter binding details, and how to forward approval prompts to Slack/Discord/Telegram (or run them as native approval clients), see Exec approvals - advanced.
Control UI editing
Use the Control UI -> Nodes -> Exec approvals card to edit defaults, per-agent overrides, and allowlists. Pick a scope (Defaults or an agent), tweak the policy, add/remove allowlist patterns, then Save. The UI shows last-used metadata per pattern so you can keep the list tidy.
The target selector chooses Gateway (local approvals) or a Node. Nodes must advertise system.execApprovals.get/set (macOS app or headless node host). If a node does not advertise exec approvals yet, edit its local approvals file directly.
Some node hosts, including the Windows companion, own a different approval policy format. Control UI shows these host-native policies read-only. Use the companion app or openclaw approvals set --node <id|name|ip> with the native policy shape to edit them; see Approvals CLI.
CLI: openclaw approvals supports gateway or node editing - see Approvals CLI.
Approval flow
When a prompt is required, the gateway broadcasts exec.approval.requested to operator clients. The Control UI and macOS app resolve it via exec.approval.resolve, then the gateway forwards the approved request to the node host.
For host=node, approval requests include a canonical systemRunPlan payload. The gateway uses that plan as the authoritative command/cwd/session context when forwarding approved system.run requests:
- The node exec path prepares one canonical plan up front.
- The approval record stores that plan and its binding metadata.
- Once approved, the final forwarded
system.runcall reuses the stored plan instead of trusting later caller edits. - If the caller changes
command,rawCommand,cwd,agentId, orsessionKeyafter the approval request was created, the gateway rejects the forwarded run as an approval mismatch.
System events and denials
Once the node signals completion, the exec lifecycle sends an Exec finished system message to the agent's session. OpenClaw can also send a progress notification after an approval is granted, following a delay of tools.exec.approvalRunningNoticeMs (default 10000; set 0 to disable it). A denied exec approval terminates the host command, meaning it never executes.
- For main-agent async approvals tied to an originating session, OpenClaw injects the denial into that session as an internal followup. This allows the agent to stop waiting on the async command and avoid a missing-result repair.
- If no session exists or the session cannot be resumed, OpenClaw can still deliver a brief denial to the operator or a direct chat route.
- Denials for subagent and cron sessions are not injected back into their session.
Gateway-host exec approvals produce the same completion lifecycle event. Approval-gated execs reuse the approval id to link the pending request to its completion or denial message (Exec finished (gateway id=...) / Exec denied (gateway id=...)).
Implications
fullis very powerful; use allowlists whenever possible.askkeeps you informed while still enabling quick approvals.- Per-agent allowlists prevent approvals from one agent from affecting another.
- Approvals only apply to host exec requests from authorized senders. Unauthorized senders cannot issue
/exec. /exec security=fullis a session-level convenience for authorized operators and intentionally bypasses approvals. To fully block host exec, set approvals security todenyor deny theexectool through tool policy.
Related
-
Exec approvals - advanced, Safe bins, interpreter binding, and forwarding approvals to chat.
-
Exec tool, Tool for running shell commands.
-
Elevated mode, Break-glass path that also skips approvals.
-
Sandboxing, Sandbox modes and workspace access.
-
Security, Security model and hardening guidance.
-
Sandbox vs tool policy vs elevated, When to use each control.
-
Skills, Auto-allow behavior backed by skills.