Skip to content

[Bug]: tools.exec.ask missing from config defaults to "on-miss", ignoring exec-approvals.json ask=off #29172

@loganprit

Description

@loganprit

Describe the bug

When tools.exec in openclaw.json does not include an ask field, the exec dispatch code defaults to "on-miss":

const configuredAsk = defaults?.ask ?? "on-miss";

This value is then passed through maxAsk(configuredAsk, ...) which always picks the stricter mode. Even though exec-approvals.json has ask: "off" at both the defaults and agent level, the gateway-side dispatch never consults exec-approvals.json defaults for the initial configuredAsk — it only reads from tools.exec.

The result: users who correctly configure exec-approvals.json with ask: "off" still get approval prompts because tools.exec.ask is missing and defaults to "on-miss".

To reproduce

  1. Set exec-approvals.json:
    {
      "defaults": { "security": "full", "ask": "off" },
      "agents": { "main": { "security": "full", "ask": "off" } }
    }
  2. Leave tools.exec in openclaw.json WITHOUT an ask field:
    { "tools": { "exec": { "host": "node", "security": "full", "node": "..." } } }
  3. Trigger an exec via Telegram or agent — approval prompt appears despite ask: "off" in exec-approvals.json

Expected behavior

When tools.exec.ask is not set, the dispatch should inherit from exec-approvals.json defaults (which has ask: "off") rather than hardcoding "on-miss".

Alternatively, openclaw doctor should warn when exec-approvals.json has ask: "off" but tools.exec.ask is missing or set to something stricter.

Workaround

Explicitly add "ask": "off" to tools.exec in openclaw.json:

{ "tools": { "exec": { "host": "node", "security": "full", "ask": "off", "node": "..." } } }

Environment

  • OpenClaw version: v2026.2.26
  • OS: macOS 26.3.0

Related issues

Code reference

The default is set in the exec dispatch entry point (appears in reply-*.js, pi-embedded-*.js, subagent-registry-*.js):

const configuredAsk = defaults?.ask ?? "on-miss";
let ask = maxAsk(configuredAsk, normalizeExecAsk(params.ask) ?? configuredAsk);

The fix from PR #26532 (resolveExplicitExecApprovalsPolicy) addresses a similar bypass but doesn't fix the initial default. A complementary fix would be to read the exec-approvals.json defaults as a fallback:

const configuredAsk = defaults?.ask ?? execApprovalsDefaults?.ask ?? "on-miss";

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions