openclaw - ✅(Solved) Fix exec-approvals allowlist doesn't match inner command when wrapped in /bin/sh -lc [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#61509Fetched 2026-04-08 02:57:48
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Author
Timeline (top)
closed ×1commented ×1cross-referenced ×1

Root Cause

None of these match because:

  1. The full allowlist path doesn't match (the exec uses ./scripts/ relative path inside the wrapper)
  2. The ./scripts/* pattern doesn't match (the outer command is /bin/sh, not ./scripts/...)
  3. /bin/sh matches the outer command but the allowlist is meant to gate the inner script

Fix Action

Workaround

Set tools.exec.security: full and tools.exec.ask: off to bypass the allowlist entirely.

PR fix notes

PR #62401: fix(exec): align node shell allowlist wrappers

Description (problem / solution / changelog)

Summary

  • Problem: host=node POSIX exec runs were wrapped in /bin/sh -lc ..., but node-host policy still treated shell wrappers as approval-required even when inner allowlist analysis succeeded.
  • Why it matters: tools.exec.security=allowlist + ask=on-miss became unusable for allowlisted node scripts and kept prompting for approval.
  • What changed: node-host now keeps POSIX shell-wrapper decisions tied to existing inner-shell allowlist analysis, while Windows cmd.exe /c wrapper detection still stays approval-gated.
  • What did NOT change (scope boundary): env-binding checks, approval replay binding, line-continuation fail-closed behavior, strict inline-eval protections, and Windows wrapper approval posture.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #61509
  • Related #58792
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: node exec precheck evaluated the original shell payload, but node-host runtime policy later blanket-blocked shell wrappers in allowlist mode and overrode successful inner-command allowlist analysis.
  • Missing detection / guardrail: there was no regression test covering an allowlisted inner POSIX script executed through the transport wrapper, and no end-to-end test protecting Windows wrapper detection after the policy change.
  • Contributing context (if known): node transport intentionally uses shell wrappers (/bin/sh -lc on POSIX, cmd.exe /d /s /c on Windows), so policy must distinguish transport wrappers from the analyzed inner command payload.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/node-host/invoke-system-run.test.ts
  • Scenario the test should lock in: allowlisted POSIX inner scripts auto-run through /bin/sh -lc, while Windows cmd.exe transport wrappers still require approval.
  • Why this is the smallest reliable guardrail: the regression lived in the parse -> policy -> execution wiring, not just pure allowlist analysis.
  • Existing test that already covers this (if any): src/node-host/exec-policy.test.ts keeps Windows-specific guidance covered at the policy layer.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • host=node allowlisted POSIX shell-wrapper commands no longer prompt unnecessarily when the inner command satisfies the allowlist.
  • Windows cmd.exe /c transport wrappers remain approval-gated.

Diagram (if applicable)

Before:
allowlisted inner script -> /bin/sh -lc wrapper -> node policy forces approval -> denied/prompted

After:
allowlisted inner script -> /bin/sh -lc wrapper -> inner payload allowlist passes -> runs

Windows remains:
allowlisted inner command -> cmd.exe /d /s /c wrapper -> approval required

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) Yes
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation:
    • The node-host allowlist decision for POSIX transport wrappers now follows the existing inner-shell allowlist analysis instead of a blanket wrapper block. Risk is unintended policy widening; mitigation is preserving existing fail-closed shell parsing/binding rules, keeping Windows cmd.exe wrappers approval-gated, and adding regression coverage for both paths.

Repro + Verification

Environment

  • OS: macOS 26.3.1 (host), simulated Windows path in test via process.platform spy
  • Runtime/container: local repo test harness
  • Model/provider: N/A
  • Integration/channel (if any): node exec path
  • Relevant config (redacted): tools.exec.security=allowlist, tools.exec.ask=on-miss, tools.exec.host=node

Steps

  1. Allowlist a node script path.
  2. Execute it via the node transport wrapper (/bin/sh -lc ...).
  3. Observe approval behavior before and after the fix.

Expected

  • POSIX allowlisted inner scripts should run without prompting.
  • Windows cmd.exe wrappers should still require approval.

Actual

  • Before: POSIX wrapped scripts still returned SYSTEM_RUN_DENIED: approval required.
  • After: POSIX wrapped scripts execute; Windows wrapper path remains approval-gated.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: manually reproduced the reported POSIX host=node wrapper failure with a temp allowlisted script before the fix, reran the same repro after the fix and confirmed execution succeeds without an approval event.
  • Edge cases checked: Windows cmd.exe transport wrappers still require approval in the seam test; targeted node/gateway approval tests still pass.
  • What you did not verify: real Windows host execution on a Windows machine.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: wrapper detection could drift again between parse-time analysis and runtime policy.
    • Mitigation: added seam coverage for both POSIX transport wrappers and Windows cmd.exe wrappers.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/node-host/exec-policy.test.ts (modified, +5/-4)
  • src/node-host/exec-policy.ts (modified, +9/-2)
  • src/node-host/invoke-system-run.test.ts (modified, +89/-1)
  • src/node-host/invoke-system-run.ts (modified, +6/-10)

Code Example

./scripts/delegate-media-image.sh "prompt" "caption"

---

/bin/sh -lc "cd \"/path/to/workspace\" && ./scripts/delegate-media-image.sh \"prompt\" \"caption\""

---

~/Library/CloudStorage/.../Workspace/scripts/*
./scripts/*
/bin/sh
RAW_BUFFERClick to expand / collapse

Bug: exec allowlist matching fails with /bin/sh -lc wrapper

Environment

  • OpenClaw 2026.4.2 (d74a122)
  • macOS 26.3.1 (arm64)
  • tools.exec.security: allowlist, tools.exec.ask: on-miss, tools.exec.host: node

Problem

When an agent calls exec with a command like:

./scripts/delegate-media-image.sh "prompt" "caption"

The gateway wraps it as:

/bin/sh -lc "cd \"/path/to/workspace\" && ./scripts/delegate-media-image.sh \"prompt\" \"caption\""

The allowlist contains patterns like:

~/Library/CloudStorage/.../Workspace/scripts/*
./scripts/*
/bin/sh

None of these match because:

  1. The full allowlist path doesn't match (the exec uses ./scripts/ relative path inside the wrapper)
  2. The ./scripts/* pattern doesn't match (the outer command is /bin/sh, not ./scripts/...)
  3. /bin/sh matches the outer command but the allowlist is meant to gate the inner script

Expected Behavior

The allowlist should match against the inner command being executed, not the /bin/sh -lc wrapper. Either:

  1. Unwrap /bin/sh -lc "..." and match against the inner command string
  2. Or match each component of a &&-chained command against the allowlist

Impact

tools.exec.ask: on-miss is completely unusable — every exec triggers an approval prompt regardless of allowlist entries. The only workaround is ask: off which disables all exec security.

This affects all agents running scripts via the gateway exec path (crons, media delegation, social outreach, etc.).

Workaround

Set tools.exec.security: full and tools.exec.ask: off to bypass the allowlist entirely.

Steps to Reproduce

  1. Configure tools.exec.security: allowlist and tools.exec.ask: on-miss
  2. Add ./scripts/* and /Users/.../scripts/* to the allowlist
  3. Have an agent call exec with ./scripts/any-script.sh
  4. Observe the approval prompt — the allowlist doesn't prevent it
  5. Check gateway logs: exec is wrapped as /bin/sh -lc "cd ... && ./scripts/any-script.sh"

extent analysis

TL;DR

The issue can be mitigated by modifying the allowlist to account for the /bin/sh -lc wrapper or by enhancing the allowlist matching logic to unwrap the inner command.

Guidance

  • Review the allowlist configuration to ensure it includes patterns that match the inner command being executed, considering the /bin/sh -lc wrapper.
  • Consider enhancing the allowlist matching logic to unwrap the inner command string from the /bin/sh -lc wrapper.
  • Evaluate the impact of setting tools.exec.security: full and tools.exec.ask: off as a temporary workaround, noting that this bypasses the allowlist entirely.
  • Investigate the possibility of matching each component of a &&-chained command against the allowlist to improve security.
  • Verify the allowlist configuration and matching logic by testing with various command patterns and wrappers.

Example

No code snippet is provided as the issue is related to configuration and logic rather than code implementation.

Notes

The provided workaround of setting tools.exec.security: full and tools.exec.ask: off bypasses the allowlist, which may not be desirable in all scenarios. A more targeted solution that enhances the allowlist matching logic or modifies the allowlist configuration is preferred.

Recommendation

Apply a workaround by modifying the allowlist configuration to include patterns that match the inner command, as this is a more targeted approach than disabling the allowlist entirely.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix exec-approvals allowlist doesn't match inner command when wrapped in /bin/sh -lc [1 pull requests, 1 comments, 2 participants]