Skip to content

Harden macOS shell wrapper allowlist parsing [AI]#78518

Merged
pgondhi987 merged 4 commits into
openclaw:mainfrom
pgondhi987:fix/fix-567
May 8, 2026
Merged

Harden macOS shell wrapper allowlist parsing [AI]#78518
pgondhi987 merged 4 commits into
openclaw:mainfrom
pgondhi987:fix/fix-567

Conversation

@pgondhi987

@pgondhi987 pgondhi987 commented May 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Describe the problem and fix in 2-5 bullets:

  • Problem: macOS exec allowlist parsing treated combined POSIX shell -c forms such as bash -xc '<payload>' as direct shell executable invocations, so an allowlist entry for the shell could satisfy the guard while the inline payload was not evaluated.
  • Why it matters: this weakens the operator's security: "allowlist" guarantee on the macOS Swift exec path and related node-host approval/allow-always binding paths.
  • What changed: shared Swift and TypeScript inline-command parsing now recognizes combined POSIX -c forms, keeps payload parsing aligned across allowlist and system-run validation, and fails closed for startup/login/interactive/fish/env-modified shell wrappers that cannot be safely bound to an inner payload.
  • What did NOT change (scope boundary): no unrelated UI, docs, CI, dependency, plugin, or model/provider behavior is changed; this PR is scoped to exec approval / shell-wrapper parsing and tests.

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

Real behavior proof (required for external PRs)

External contributors must show after-fix evidence from a real OpenClaw setup. Unit tests, mocks, lint, typechecks, snapshots, and CI are supplemental only. Screenshots are encouraged even for CLI, console, text, or log changes; terminal screenshots and copied live output count. Be mindful of private information like IP addresses, API keys, phone numbers, non-public endpoints, or other private details when providing evidence.

  • Behavior or issue addressed: macOS Swift shell-wrapper parser now treats combined POSIX -c forms as wrappers and exposes the inline payload to allowlist resolution instead of matching only the shell executable.
  • Real environment tested: local macOS machine with Xcode 26.4.1, Apple Swift 6.3.1, arm64.
  • Exact steps or command run after this patch: compiled and ran a direct Swift parser harness against the actual base and head parser sources for [/bin/bash, -c, /usr/bin/printf safe_marker] and [/bin/bash, -xc, /usr/bin/printf safe_marker].
  • Evidence after fix: copied terminal output from the macOS Swift harness:
    Base: baseline isWrapper=true command=/usr/bin/printf safe_marker
    Base: combined isWrapper=false command=nil
    Head: baseline isWrapper=true command=/usr/bin/printf safe_marker
    Head: combined isWrapper=true command=/usr/bin/printf safe_marker
    
  • Observed result after fix: the combined POSIX -c form now resolves to /usr/bin/printf safe_marker, so allowlist evaluation sees the payload executable instead of matching only /bin/bash; unbindable startup/login/env-modified shell wrapper shapes fail closed rather than minting payload-only allowlist or approval entries.
  • What was not tested: broad full-suite gates were not run locally; validation stayed focused on the changed exec approval and shell-wrapper surfaces.
  • Before evidence (optional but encouraged): the base harness reproduced the reported behavior with combined isWrapper=false command=nil for /bin/bash -xc /usr/bin/printf safe_marker.

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: the macOS Swift shell-wrapper allowlist parser only recognized exact POSIX inline-command tokens such as -c / -lc, while valid combined short option forms containing c were treated as ordinary shell invocations.
  • Missing detection / guardrail: allowlist and display/raw-command validation had separate inline-command parsing logic, allowing parser drift between execution validation and allowlist resolution.
  • Contributing context (if known): payload-only allow-always and durable approval binding need stricter treatment for shell startup forms because login/interactive/fish/env-modified wrappers can execute wrapper-side startup code before the inline payload.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file:
    • apps/macos/Tests/OpenClawIPCTests/ExecAllowlistTests.swift
    • apps/macos/Tests/OpenClawIPCTests/ExecSystemRunCommandValidatorTests.swift
    • src/infra/shell-inline-command.test.ts
    • src/infra/exec-approvals-allow-always.test.ts
    • src/infra/system-run-command.test.ts
    • src/node-host/invoke-system-run-plan.test.ts
    • test/fixtures/system-run-command-contract.json
  • Scenario the test should lock in: combined POSIX -c forms parse to the inline payload for allowlist resolution; startup/login/env-modified wrappers and positional carriers do not bypass allowlist/allow-always approval binding.
  • Why this is the smallest reliable guardrail: it exercises the parser and allowlist binding seams directly on both Swift and TypeScript implementations without requiring a full host exec E2E run.
  • Existing test that already covers this (if any): existing shell-wrapper tests covered exact -c / -lc; this PR adds combined-form and blocked-wrapper regressions.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Exec allowlist mode is stricter for shell-wrapper commands. Combined POSIX -c forms are evaluated against their inline payloads, and unsafe startup/login/env-modified shell wrappers may require explicit approval instead of being satisfied by a shell executable or payload-only allow-always entry.

Diagram (if applicable)

Before:
[system.run bash -xc payload] -> [macOS allowlist resolves /bin/bash] -> [payload not checked]

After:
[system.run bash -xc payload] -> [parser extracts payload] -> [allowlist checks payload executable]

Blocked forms:
[startup/login/env-modified shell wrapper] -> [cannot bind payload safely] -> [approval/allowlist miss]

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: command execution approval and allowlist parsing is tightened. The compatibility risk is that previously accepted shell-wrapper shapes may now prompt or fail closed; mitigation is preserving safe generated legacy sh -lc raw-payload binding and adding focused Swift/TS regression coverage.

Repro + Verification

Environment

  • OS: macOS on arm64
  • Runtime/container: Xcode 26.4.1, Apple Swift 6.3.1, Node.js v22.22.2
  • Model/provider: N/A
  • Integration/channel (if any): macOS exec host / node-host system.run
  • Relevant config (redacted): exec security: "allowlist"; allowlist includes a POSIX shell executable for the original bypass scenario.

Steps

  1. Compile/run a direct Swift parser harness against base and head parser sources with [/bin/bash, -c, /usr/bin/printf safe_marker] and [/bin/bash, -xc, /usr/bin/printf safe_marker].
  2. Run focused macOS Swift tests for ExecAllowlistTests and ExecSystemRunCommandValidatorTests.
  3. Run focused TypeScript parser, allowlist, command analysis, node-host approval-plan, and system-run tests.
  4. Run targeted typecheck, formatter check, whitespace check, and codex review --base origin/main.

Expected

  • Exact -c and combined POSIX -c forms both expose the inline payload for allowlist evaluation.
  • Unsafe startup/login/env-modified wrapper forms fail closed for payload-only allowlist/approval binding.

Actual

  • Base parser reproduced the bug: combined form returned isWrapper=false command=nil.
  • Head parser returns isWrapper=true command=/usr/bin/printf safe_marker for the combined form.
  • Focused Swift and TypeScript checks passed.

Evidence

Attach at least one:

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

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: combined POSIX -c macOS parser behavior; Swift allowlist/system-run validator tests; TypeScript shell parser, allowlist/allow-always, command explainer/risk, system-run, and node-host approval-plan behavior; codex review --base origin/main.
  • Edge cases checked: -xc, -ec, -euxc, -cx, options with separate values such as -O/-o, rawless sh -lc, legacy generated sh -lc raw-payload binding, env-modified shell wrappers, login/interactive wrappers, fish init/attached command forms, and positional carriers.
  • What you did not verify: broad full-suite gates and live end-to-end execution through a production-installed OpenClaw gateway.

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes, with stricter approval prompts for unsafe shell-wrapper forms.
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: stricter shell-wrapper binding may cause additional approval prompts for commands that previously matched a broad shell allowlist entry.
    • Mitigation: preserve safe generated legacy sh -lc raw-payload binding and cover blocked forms with focused Swift/TS tests.
  • Risk: Swift and TypeScript parser behavior could drift again.
    • Mitigation: shared contract fixture coverage plus mirrored parser tests on both implementations.

@openclaw-barnacle openclaw-barnacle Bot added app: macos App: macos size: S maintainer Maintainer-authored PR labels May 6, 2026
@clawsweeper

clawsweeper Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Summary
The PR adds shared Swift and TypeScript shell inline-command parsing, routes macOS allowlist and node-host approval binding through bindable wrapper parsing, fails closed for unsafe shell-wrapper forms, and adds focused regression coverage.

Reproducibility: yes. Current-main source shows the wrapper parser only checks exact POSIX inline flags while the validator already handles combined c flags, and the PR body includes base/head Swift harness output showing bash -xc is only extracted on head.

Real behavior proof
Sufficient (terminal): The PR body now includes copied terminal output from a local macOS Swift harness showing base versus head parser behavior, and the latest Real behavior proof check succeeded.

Next step before merge
A repair worker can make the single missing changelog entry if a maintainer wants automation; code/security review still needs normal maintainer and CI gating.

Security
Cleared: No concrete supply-chain, secret-handling, permission, or command-execution regression was found in the latest diff; the branch tightens approval parsing and now denies blocked shell wrappers before approval planning.

Review findings

  • [P3] Add the missing changelog entry — apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift:43-50
Review details

Best possible solution:

Land a maintainer-reviewed version that preserves Swift/TypeScript parser parity and blocked-wrapper fail-closed behavior, adds the Unreleased changelog entry, and waits for exact-head CI/touched-surface checks.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main source shows the wrapper parser only checks exact POSIX inline flags while the validator already handles combined c flags, and the PR body includes base/head Swift harness output showing bash -xc is only extracted on head.

Is this the best way to solve the issue?

Mostly yes. Sharing the inline parser between Swift and TypeScript paths and denying unbindable startup/env shell wrappers is a narrow maintainable fix; the remaining issue is the missing changelog entry plus normal maintainer and CI gating.

Full review comments:

  • [P3] Add the missing changelog entry — apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift:43-50
    This changes user-visible macOS exec allowlist behavior and is marked as bug/security hardening, but the branch still does not update CHANGELOG.md. Repo policy requires user-facing fixes and hardening changes to be recorded under Unreleased before merge.
    Confidence: 0.88

Overall correctness: patch is correct
Overall confidence: 0.86

Acceptance criteria:

  • git diff --check

What I checked:

  • Protected label: The live PR metadata for head 3e69e72 includes maintainer, so this cleanup workflow must keep the PR open for explicit maintainer handling. (3e69e7249d6e)
  • Current-main parser gap: Current main's Swift wrapper parser only accepts exact POSIX inline flags from command[1], so combined forms such as bash -xc <payload> are not extracted on this allowlist path. (apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift:74, 95a1c915312a)
  • Existing validator drift: Current main's Swift system-run validator already contains combined c flag handling, supporting the PR premise that wrapper parsing had drifted from another validation path. (apps/macos/Sources/OpenClaw/ExecSystemRunCommandValidator.swift:353, 95a1c915312a)
  • Latest-head blocked-wrapper denial: The latest PR head denies blocked shell-wrapper approval plans before hardening when command.shellPayload is null and isBlockedShellWrapperCommand(command.argv) is true, addressing the earlier hidden-payload concern in the node-host approval planner. (src/node-host/invoke-system-run-plan.ts:1307, 3e69e7249d6e)
  • Latest-head parser implementation: The PR head adds allowlist-specific Swift extraction and a shared inline parser path for combined POSIX c flags, with startup wrapper blocking before payload extraction. (apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift:43, 3e69e7249d6e)
  • Real behavior proof check: GitHub check runs for the latest head show Real behavior proof completed successfully after earlier failures, and the PR body includes copied macOS Swift harness output comparing base and head parser behavior. (3e69e7249d6e)

Likely related people:

  • steipete: Recent path history shows repeated work on macOS exec approvals, shell wrapper parity, and shared shell-wrapper traversal, including the current Swift parser and TypeScript shell-wrapper resolution surfaces. (role: recent maintainer and security-hardening owner; confidence: high; commits: a96d89f34383, a94ec3b79be9, 0f1a938a3eec; files: apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift, apps/macos/Tests/OpenClawIPCTests/ExecAllowlistTests.swift, src/infra/shell-wrapper-resolution.ts)
  • ngutman: Authored merged macOS exec command parity work touching the same validator and allowlist test surface that this PR now aligns with wrapper parsing. (role: adjacent macOS parity contributor; confidence: medium; commits: c4a4050ce48b, de6bac331cde; files: apps/macos/Sources/OpenClaw/ExecSystemRunCommandValidator.swift, apps/macos/Tests/OpenClawIPCTests/ExecAllowlistTests.swift, src/infra/shell-wrapper-resolution.ts)
  • obviyus: Recent current-main history shows work on node-host shell payload mutability checks in the approval planning area affected by this PR's fail-closed binding changes. (role: node-host approval binding maintainer; confidence: medium; commits: 75c551e89e67; files: src/node-host/invoke-system-run-plan.ts)
  • pgondhi987: Although this is the PR author, current-main history also includes earlier merged shell-wrapper security work by the same contributor on src/infra/shell-wrapper-resolution.ts, making them relevant for follow-up context. (role: adjacent prior security contributor; confidence: medium; commits: 8f8492d172f4, 666f48d9b882; files: src/infra/shell-wrapper-resolution.ts, src/node-host/invoke-system-run-plan.ts)

Remaining risk / open question:

  • Exact-head CI was still unstable with several check runs queued at inspection time, so maintainers should wait for required checks before merge.
  • The PR proof is focused on a macOS Swift parser harness and touched Swift/TypeScript tests; it does not show a full production-installed Gateway or macOS app end-to-end run.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 95a1c915312a.

Re-review progress:

@pgondhi987

Copy link
Copy Markdown
Contributor Author

Not applicable; changelog is handled at merge time.

Quoted comment from @clawsweeper:

Codex review: needs real behavior proof before merge.

Summary
The PR adds a Swift inline-command parser, rewires macOS shell wrapper and validator parsing to recognize combined POSIX c flags, and adds allowlist regression tests.

Reproducibility: yes. from source inspection: current main only recognizes exact POSIX inline flags in the wrapper parser, so a combined form such as bash -xc /usr/bin/printf falls back to the shell executable instead of the payload. I did not execute the Swift test lane.

Real behavior proof
Needs real behavior proof before merge: The PR body explicitly says no real environment, Swift test execution, or macOS runtime execution was run, so after-fix real behavior proof is missing. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, ask a maintainer to comment @clawsweeper re-review.

Next step before merge
The protected maintainer label and missing external real-behavior proof require maintainer/contributor follow-up rather than an automated repair lane.

Security
Cleared: No concrete supply-chain or security regression was found in the diff; it touches command execution policy parsing but adds no dependencies, permissions, network calls, or credential handling.

Review findings

  • [P3] Add the required changelog entry — apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift:80-83
Review details

Best possible solution:

Land a maintainer-reviewed version that preserves Swift/TypeScript parser parity, adds the Unreleased changelog entry, and includes macOS Swift test or runtime proof.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection: current main only recognizes exact POSIX inline flags in the wrapper parser, so a combined form such as bash -xc /usr/bin/printf falls back to the shell executable instead of the payload. I did not execute the Swift test lane.

Is this the best way to solve the issue?

Mostly yes: sharing the inline-command matcher between wrapper parsing and validation is a narrow maintainable fix for the drift. It still needs the missing changelog and real macOS/Swift behavior proof before merge.

Full review comments:

  • [P3] Add the required changelog entry — apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift:80-83
    This changes user-visible macOS exec allowlist behavior and is marked as bug/security hardening, but the diff does not update CHANGELOG.md. Repo policy requires user-facing fixes and hardening changes to be recorded under Unreleased before merge.
    Confidence: 0.88

Overall correctness: patch is correct
Overall confidence: 0.78

Acceptance criteria:

  • cd apps/macos && swift test --filter ExecAllowlistTests
  • Real macOS allowlist-mode check showing a combined POSIX c flag resolves the payload executable instead of the shell binary

What I checked:

  • Protected label: The PR is labeled maintainer, so this cleanup workflow must keep it open for explicit maintainer handling. (98ddc0dd8e35)
  • Current-main gap: Current main only accepts an exact POSIX inline flag in command[1], so bash -xc <payload> is not treated as a shell wrapper payload on this path. (apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift:74, 99b17263a12d)
  • Existing drift evidence: The validator path on current main already has combined c-flag matching logic, which supports the PR's claim that the wrapper parser drifted from another Swift path. (apps/macos/Sources/OpenClaw/ExecSystemRunCommandValidator.swift:334, 99b17263a12d)
  • PR proof gap: The PR body says no real environment, Swift test execution, or macOS runtime execution was run; only regression coverage was added. (98ddc0dd8e35)
  • Missing changelog: A search found existing exec-approval changelog entries but no entry for this macOS allowlist parsing change under Unreleased. (CHANGELOG.md:1, 99b17263a12d)
  • Feature history: GitHub path history points to recent exec approval hardening and wrapper parity work by steipete and ngutman, including commits a94ec3b7, 55cf9257, a96d89f3, and c4a4050c.

Likely related people:

  • steipete: Authored multiple recent commits in the macOS exec approvals and wrapper-resolution area, including security hardening and wrapper parity work. (role: recent maintainer and security-hardening owner; confidence: high; commits: a94ec3b79be9, 55cf92578d26, a96d89f34383; files: apps/macos/Sources/OpenClaw/ExecShellWrapperParser.swift, apps/macos/Sources/OpenClaw/ExecSystemRunCommandValidator.swift, apps/macos/Tests/OpenClawIPCTests/ExecAllowlistTests.swift)
  • ngutman: Authored the merged macOS exec command parity work that touched the same validator and allowlist test surface. (role: adjacent feature contributor; confidence: medium; commits: c4a4050ce48b; files: apps/macos/Sources/OpenClaw/ExecSystemRunCommandValidator.swift, apps/macos/Tests/OpenClawIPCTests/ExecAllowlistTests.swift)

Remaining risk / open question:

  • The PR changes security-sensitive command allowlist parsing without attached after-fix macOS or Swift runtime proof.
  • The required user-facing changelog entry is missing.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 99b17263a12d.

@pgondhi987
pgondhi987 force-pushed the fix/fix-567 branch 5 times, most recently from b26c6db to cbedc1b Compare May 7, 2026 08:54
@openclaw-barnacle openclaw-barnacle Bot added the app: web-ui App: web-ui label May 7, 2026
@pgondhi987
pgondhi987 force-pushed the fix/fix-567 branch 3 times, most recently from 276d314 to 06e9592 Compare May 7, 2026 11:23
@pgondhi987
pgondhi987 requested a review from a team as a code owner May 7, 2026 11:23
@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime cli CLI command changes extensions: codex size: XL and removed size: L labels May 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed app: web-ui App: web-ui gateway Gateway runtime cli CLI command changes extensions: codex labels May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@pgondhi987
pgondhi987 merged commit fc065b2 into openclaw:main May 8, 2026
22 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* fix: harden shell wrapper allowlist parsing

* fix: harden shell wrapper approval binding

* docs: add changelog entry for PR merge

---------

Co-authored-by: Ishaan <[email protected]>
rogerdigital pushed a commit to rogerdigital/openclaw that referenced this pull request May 9, 2026
* fix: harden shell wrapper allowlist parsing

* fix: harden shell wrapper approval binding

* docs: add changelog entry for PR merge

---------

Co-authored-by: Ishaan <[email protected]>
lykeion-dev pushed a commit to lykeion-dev/openclaw--rev that referenced this pull request May 14, 2026
* fix: harden shell wrapper allowlist parsing

* fix: harden shell wrapper approval binding

* docs: add changelog entry for PR merge

---------

Co-authored-by: Ishaan <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
* fix: harden shell wrapper allowlist parsing

* fix: harden shell wrapper approval binding

* docs: add changelog entry for PR merge

---------

Co-authored-by: Ishaan <[email protected]>
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
* fix: harden shell wrapper allowlist parsing

* fix: harden shell wrapper approval binding

* docs: add changelog entry for PR merge

---------

Co-authored-by: Ishaan <[email protected]>
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
* fix: harden shell wrapper allowlist parsing

* fix: harden shell wrapper approval binding

* docs: add changelog entry for PR merge

---------

Co-authored-by: Ishaan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: macos App: macos maintainer Maintainer-authored PR proof: sufficient ClawSweeper judged the real behavior proof convincing. size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant