One of the most confusing OpenClaw moments looks like this:
- you set
tools.exec.security: "full", - you set
tools.exec.ask: "off", - and the command still fails with something like
allowlist miss.
That feels contradictory, but it usually is not.
The reason is simple: exec has more than one gate.
This guide is the practical map.
If your broader problem is optional tools/plugins rather than host exec specifically, also read:
If the behavior changed right after an upgrade, also keep these two nearby:
What this guide helps you finish
By the end of this guide, you should be able to do three things without guessing:
- identify which layer is actually blocking
exec, - update approvals on the machine that really enforces them,
- verify that the fix preserved a sane trust boundary instead of just making the error disappear.
Who this is for (and not for)
Use this guide if any of these are true:
- OpenClaw says
allowlist misseven though your runtime config looks permissive, - the gateway host and node host behave differently,
- you are deciding whether a binary belongs in an allowlist or in
safeBins, - you want to unblock execution without quietly turning a host into a free-for-all.
This guide is not the best starting point if your real problem is that the tool itself is disabled, missing, or misconfigured. In that case, start with the tool-specific guide or troubleshooting page first, then come back here if approvals still block execution.
Before you change approvals: collect these four facts
Before you touch config, write down:
- Which machine actually ran the command attempt: sandbox, gateway host, or node host?
- Which binary path is being blocked: the exact interpreter or CLI, not the script you hoped to run through it.
- What trust posture you are aiming for: strict allowlist, trusted solo host, or something in between.
- What success should look like: one command works once, or the host can now execute this class of command reliably?
This tiny prep step prevents the most common mistake on this topic: changing the wrong layer on the wrong machine.
1) The four layers people collapse into one
When people say âexec is blockedâ, they often mean one of four different things:
- tool policy â is the tool allowed for this agent at all?
- sandbox/runtime â does it run in sandbox, gateway host, or node host?
- elevated mode â are you allowing host execution or approval skipping in this session?
- exec approvals â does the execution host itself allow this command path?
Those are not synonyms.
If you debug them as if they were one switch, you will keep making the wrong change.
2) Exec approvals live on the execution host
This is the most important fact:
- if the command runs on the gateway host, approvals are enforced there,
- if the command runs on a node host, approvals are enforced on that node host.
The local approvals file lives at:
~/.openclaw/exec-approvals.json
So when a command is blocked, ask first:
Which machine actually tried to execute it?
Do not assume the answer is âthe machine where I edited openclaw.json.â
This is especially important if your setup already involves nodes for remote browser control or other split-host behavior:
3) Why tools.exec.security="full" can still feel blocked
OpenClawâs runtime tools.exec.* settings and the hostâs exec approvals are separate inputs.
In practice, the effective approvals posture is the stricter result.
That means a host-local approvals file can still keep you in an allowlist-driven world even when your agent config feels permissive.
Practical takeaway:
- if you see
allowlist miss, do not assume your JSON config was ignored, - assume the execution host still requires an allowlist match or prompt path,
- and inspect approvals next.
4) The fastest fix for allowlist miss
If the binary should really be allowed, add it explicitly with the approvals CLI.
Examples:
openclaw approvals allowlist add --agent main "/opt/homebrew/bin/node"
openclaw approvals allowlist add --agent main "/bin/bash"
openclaw approvals allowlist add --agent main "/usr/bin/python3"
If the command runs on a node host instead of the gateway host:
openclaw approvals allowlist add --agent main --node <id|name|ip> "/usr/bin/python3"
This is usually the right move for:
- interpreters,
- package managers,
- wrapper CLIs,
- and trusted operator binaries you actually mean to run.
5) Do not use safeBins as a trust bypass for interpreters
safeBins is easy to misunderstand.
It is meant for a small class of stdin-only filter binaries, such as stream processors.
It is not meant for:
python3nodebashshzshruby- or other runtimes that can evaluate code, spawn subcommands, or read files by design.
If a binary is powerful, give it an explicit allowlist entry instead of trying to sneak it through safeBins.
That keeps the trust boundary honest.
6) What safeBins is actually good for
Use safeBins for narrow, predictable filters where stdin-only behavior is the whole point.
The mental model is:
- a stream comes in,
- a tightly constrained binary transforms it,
- and the binary does not turn into a generic filesystem/code execution escape hatch.
If your command needs arbitrary file paths, script evaluation, or runtime shells, you are already outside the âsafe binâ model.
7) Trust model choices that make sense in real life
Option A: strict operator posture
Best when:
- the host is sensitive,
- multiple workflows share it,
- or you want every powerful command path to be explicit.
Recommended posture:
- approvals in
allowlistmode, - prompts on miss,
- interpreters explicitly allowlisted,
- minimal use of
safeBins.
Option B: trusted solo-operator host
Best when:
- this is your own tightly controlled machine,
- you understand the blast radius,
- and speed matters more than frequent prompting.
You may still choose broader approvals defaults, but do so deliberately â not because you confused tools.exec.security with host approvals.
Before broadening trust on a machine you care about, create a rollback point for your config/state first:
8) Common failure patterns
âIt works in my shell, but OpenClaw says allowlist missâ
That usually means:
- the shell is not the enforcement point,
- the gateway/node host is,
- and that hostâs approvals file still requires an allowlist match.
âI added python3 to safeBins and it still feels wrongâ
That is the wrong trust model.
Move it to an explicit allowlist entry.
âThe gateway host works, but the node host still blocksâ
Those are two different approval stores.
Fix the node hostâs approvals, not just the gateway config.
9) A safe debugging order
When exec behavior is confusing, use this order:
- confirm the tool is allowed for the agent,
- confirm where it is executing (sandbox / gateway / node),
- check whether elevated mode changes anything,
- inspect or update exec approvals on the actual execution host,
- only then tweak
safeBinsor broader trust settings.
That order usually cuts the debugging time in half.
10) A quick decision rule for allowlist vs safeBins
If the binary can interpret code, read arbitrary files, spawn subcommands, or act like a general-purpose runtime, treat it as an allowlist candidate.
If the binary is a narrow stdin-only filter whose value comes from constrained transformation rather than open-ended execution, it may belong in safeBins.
When in doubt, choose the more explicit trust posture first. It is much easier to deliberately loosen a boundary later than to discover you quietly widened one without noticing.
Verification checklist after the fix
Do not stop at âthe error went away once.â Verify that:
- the same command now succeeds on the intended execution host
- the blocked binary path matches the one you actually approved
- the gateway and node host behave consistently with your chosen trust posture
- interpreters and powerful CLIs were allowlisted explicitly, not smuggled into
safeBins - you can explain why this fix works, not just which command made the error disappear
Quick checklist
- I know whether the command runs on sandbox, gateway host, or node host
- I am editing approvals on the actual execution host
- I use allowlists for interpreters and powerful CLIs
- I reserve
safeBinsfor stdin-only filters - I am not treating
tools.exec.securityas the only gate