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, the tools.exec value applies. Host exec also uses the local approvals state on that machine. A host-local ask: "always" in the execution host approvals file keeps prompting, even if the session or config defaults request ask: "on-miss".

Where it applies

Exec approvals are applied locally on the execution host:

  • Gateway host -> the openclaw process 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.run to the macOS app over local IPC.
  • The macOS app enforces approvals and runs the command within the UI context.

Inspecting the effective policy

CommandWhat it shows
openclaw approvals get / --gateway / --node <id|name|ip>The requested policy, host policy sources, and the effective result.
openclaw exec-policy showA merged view from the local machine.
openclaw exec-policy set / presetSync the local requested policy with the local host approvals file in a single step.

Note

Per-session /exec overrides are excluded. Run /exec in 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:

ValueBehavior
denyBlock host exec.
allowlistRun only allowlisted commands without prompting.
askApply the allowlist policy and ask on misses.
autoApply 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.
fullRun 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), deny stops all host exec requests. allowlist permits only commands on the allowlist. full grants unrestricted access (same as elevated). The default is full for gateway or node hosts; a sandbox host uses deny as its default.

exec.ask

  • ask (off" | "on-miss" | "always), Determines the ask policy for host exec. This controls how approval prompts behave by default from tools.exec.ask and the host approvals defaults. Defaults to off. The per-call ask tool parameter (see Exec tool) can only make that baseline stricter, and channel-origin model calls ignore it when the effective host ask is off. off means no prompt ever appears. on-miss prompts only when the allowlist does not match. always prompts for every command. When the effective ask mode is always, allow-always durable 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 is deny. deny blocks the request. allowlist allows it only if the allowlist matches. full allows it unconditionally.

tools.exec.strictInlineEval

  • strictInlineEval (boolean), When true, 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 affect security, 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.

LayerYOLO setting
tools.exec.modefull on gateway/node
Host askFallbackfull

Warning

Key differences:

  • tools.exec.host=auto determines where execution occurs: in a sandbox when possible, otherwise through the gateway.
  • YOLO dictates how host-level execution gets approved: using security=full in combination with ask=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.
  • auto does not allow gateway routing to be freely overridden from within a sandboxed session. A per-call host=node request is permitted from auto; host=gateway is only permitted from auto when no sandbox runtime is currently active. For a stable non-auto default, either configure tools.exec.host or 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-policy does not sync node approvals.
  • openclaw exec-policy set --host node is 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=off affects only the current session.
  • /elevated full acts as a break-glass shortcut that bypasses exec approvals only when both the requested policy and the host approvals file resolve to security: "full" and ask: "off". A more restrictive host file, such as ask: "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:

FieldMeaning
patternResolved binary path glob or bare command-name glob
argPatternECMAScript argv regex or generated exact-argv hash; omitted is path-only
idStable opaque ID; generated as a UUID when absent
sourceGenerated entry source, such as allow-always; omit for manual entries
commandTextLegacy plaintext input; discarded during load
lastUsedAtLast-used timestamp
lastUsedCommandLast command that matched; omitted for generated hashed argv entries
lastResolvedPathLast 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: false and 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.run call reuses the stored plan instead of trusting later caller edits.
  • If the caller changes command, rawCommand, cwd, agentId, or sessionKey after 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

  • full is very powerful; use allowlists whenever possible.
  • ask keeps 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=full is a session-level convenience for authorized operators and intentionally bypasses approvals. To fully block host exec, set approvals security to deny or deny the exec tool through tool policy.