OpenClaw Found a One-Line Security Bug Hiding in Its Exec Approval Policy

OpenClaw Found a One-Line Security Bug Hiding in Its Exec Approval Policy

Agent security usually gets sold as a dramatic thing: poisoned prompts, rogue tools, malicious plugins, exfiltrated tokens, screenshots full of secrets. OpenClaw PR #91286 is more uncomfortable because it is smaller than that. It fixes a one-line rank inversion in exec approval policy code. No cinematic exploit chain. No scary payload. Just an ordering table that said, in effect, that deny was less restrictive than full.

That is exactly the kind of bug that matters in agent platforms. The security boundary is not just the model refusing bad requests. It is the glue code that decides which shell policy wins when a request, a session override, an agent default, and a node host all meet at runtime. If that glue code lies, the rest of the control plane becomes theater with better icons.

The patch changes one line in src/infra/exec-approvals.ts: const order = { deny: 0, allowlist: 1, full: 2 } becomes const order = { full: 0, allowlist: 1, deny: 2 }. The pull request was opened on June 8 at 01:00:52 UTC, roughly ten minutes after issue #91283 described the inversion. The issue is labeled security-impacting, and for once the label does not need exaggeration to earn its keep.

The dangerous part is not that the bug was permissive

The obvious reading is backwards: if the order is inverted, maybe OpenClaw accidentally allowed too much. But the concrete failure mode described by the issue is subtler. A session-level override of exec.security="full" could be clamped back to the agent default of allowlist. The system could become stricter than the operator requested.

That still belongs in the security bucket. Security systems are not only dangerous when they under-enforce. They are also dangerous when they become unpredictable, because operators respond to unpredictability with broader defaults, manual bypasses, or superstition. If a trusted maintenance session says full but behaves like allowlist, the next move is often not a careful local fix. It is changing the global setting, adding a larger allowlist, or turning approval prompts into rubber stamps because the narrow path failed.

The affected call path is resolveExecHostApprovalContext, where hostSecurity = minSecurity(params.security, approvals.agent.security) chooses how request/session policy interacts with the agent default. The same file already had execSecurityFloorRank using the correct conceptual order — full=0, allowlist=1, deny=2 — which makes this less a design debate than an internal inconsistency. The platform had two maps for the same policy semantics. One of them told the truth.

Approval policy is infrastructure, not prompt furniture

This is the part agent teams should take personally. Approval systems are increasingly the real safety mechanism for coding agents. The model can suggest. The orchestrator decides whether the suggestion gets a shell, a browser, a filesystem, an MCP server, or a remote node. That decision has to be boringly deterministic across layers.

OpenClaw users have already filed related reports. Issues #58691 and #59079 describe users setting exec.security: "full" and ask: "off" while still hitting approval or allowlist enforcement in older 2026.3.31-era installs. Not every historical symptom necessarily flows from this exact line, but the pattern is familiar: the config says one thing, the runtime does another, and users are left debugging policy by vibes.

That is not acceptable for agent operations. If you are running scheduled agents, maintenance bots, self-hosted coding assistants, or node-executed workflows, approval behavior is part of the service contract. A harmless healthcheck should not get stranded because a session override was silently narrowed. A sensitive shell command should not slip through because two merge helpers interpreted the same enum differently. The only tolerable state is that operators can predict which policy wins before they press enter.

For teams building on OpenClaw today, the practical move is simple: verify behavior, not just configuration. If you rely on exec.security="full" for a trusted local lane, run a harmless command through that exact lane and confirm whether it executes directly, prompts, or allowlist-fails. If you rely on allowlist, test both allowed and disallowed commands. If you rely on deny, test that the denial survives session overrides. Approval policies should have smoke tests the same way deployment pipelines do.

The test should encode the names, not the implementation accident

The engineering lesson is that enum names with policy meaning deserve semantic tests. full, allowlist, and deny are not arbitrary strings. They encode operator intent and organizational risk posture. A test that merely exercises a branch is not enough; the test needs to say, in plain terms, that deny is most restrictive, allowlist is in the middle, and full is least restrictive. Otherwise the next refactor can preserve code coverage while breaking the contract humans actually depend on.

This is also where agent security differs from traditional application security. A web app permission bug may affect a request path. An agent approval bug affects decision-making across turns: one model turn proposes a command, another policy layer evaluates it, a channel-specific approval client may or may not exist, and a session setting may override a global default. The attack surface is not a function. It is a choreography.

OpenClaw deserves credit for the speed here. The issue was filed with a minimal reproduction shape and a precise code quote; the pull request landed minutes later. ClawSweeper started reviewing immediately. That is the response profile you want around approval code. But the fix should also prompt a wider audit: search for other duplicated rank maps, policy min/max helpers, and config merge functions where a human word like “stricter” or “weaker” is encoded as an integer.

The bigger take is not that OpenClaw had a one-line bug. Everyone has one-line bugs. The take is that agent platforms are now mature enough that one-line bugs can sit directly on the operator trust boundary. A permission system that cannot reliably express “this session is allowed to run full exec” or “this agent may never run exec” is not a security feature yet. It is an aspiration.

LGTM for the fix. Request changes for every approval system that still treats policy ranking as a private implementation detail instead of a contract with the operator.

Sources: OpenClaw PR #91286, OpenClaw issue #91283, OpenClaw issue #58691, OpenClaw issue #59079