Skip to content

feat: replace legacy exec approvals with V2 - #1051

Open
bkudiess wants to merge 5 commits into
openclaw:mainfrom
bkudiess:bkudiess-v2-exec-approvals-pr
Open

feat: replace legacy exec approvals with V2#1051
bkudiess wants to merge 5 commits into
openclaw:mainfrom
bkudiess:bkudiess-v2-exec-approvals-pr

Conversation

@bkudiess

@bkudiess bkudiess commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replace the legacy Windows exec-approval policy and prompt path with the V2 coordinator, store, and hardened dialog introduced by feat: add exec approval prompt dialog for system.run on the Windows node #1045.
  • Make low-level system.run and system.run.prepare canonical argv-only, matching the upstream gateway contract.
  • Execute canonical argv through Local and MXC runners, including cmd-aware serialization for cmd.exe /d /s /c.
  • Port macOS parity hardening for secret redaction, display bounds, bypass detection, one-shot decisions, policy currency, audit-suppression approval, path display, and attended-desktop detection.
  • Align fresh effective policy with macOS: empty allowlist, prompt on miss when attended, deny fallback when unattended. Malformed, untrusted, and migration-failed paths remain hard deny.
  • Make the Windows V1 cutover explicit: legacy command-text rules are left untouched but are not evaluated or converted; prior allows require attended V2 reapproval and unattended calls deny.
  • Move Permissions policy editing onto the App-owned V2 store with single-read hashing, CAS, explicit UI deltas, alternate-state path support, and remote grant restrictions.
  • Remove the legacy V1 policy, prompt service, settings flag, tests, and runtime fallback.

Architecture ownership

  • Old owner: SystemCapability, ExecApprovalPolicy, and ExecApprovalPromptService split approval text matching, prompting, and shell execution across parallel paths.
  • New owner: ExecApprovalsCoordinator owns authorization; ExecApprovalsStore owns policy persistence/CAS; ExecApprovalV2UiPromptHandler and ExecApprovalDialog own presentation; runners receive only the approved execution payload.
  • Preserved invariant: the resolved canonical argv approved by V2 is the argv executed by the selected runner. Missing resolution, changed policy, unsupported transport, unsafe persistence, or presentation failure denies execution.

Behavior changes

  • Low-level callers must send command as string[] argv. The normal gateway exec host=node path already wraps Windows command strings as ["cmd.exe","/d","/s","/c",command].
  • Raw MCP, direct node.invoke, plugin, and winnode callers migrate from {"command":"echo hello","shell":"cmd"} to {"command":["cmd.exe","/d","/s","/c","echo hello"],"rawCommand":"echo hello"}. String requests return command-array-required.
  • A fresh valid policy defaults to security=allowlist, ask=on-miss, askFallback=deny, and an empty allowlist. Only truly missing trustworthy state gets this default; invalid or unreadable active/legacy paths fail closed to security=deny.
  • Non-empty custom env is rejected until environment values can be identity-bound and displayed safely.
  • Shells and script/code interpreters can be approved once, but cannot receive reusable executable-only grants.
  • Remote system.execApprovals.set may preserve/remove existing grants and preserve/tighten effective policy, but cannot add/change grants or weaken security, ask, askFallback, or autoAllowSkills.
  • The active V2 store defaults to %APPDATA%\OpenClawTray\exec-approvals.json; OPENCLAW_STATE_DIR overrides it.

Upgrade contract

Windows V1 exec-policy.json command-text globs are intentionally retired without migration.

  • V1 files remain byte-for-byte untouched during normal runtime.
  • No V1 allow or deny rule is imported into V2.
  • A fresh valid V2 policy uses an empty allowlist with prompt-on-miss and deny fallback.
  • Prior V1 allows require attended V2 reapproval; unattended calls deny.
  • Prior V1 denies are not imported and may be explicitly superseded by an attended V2 approval.
  • Existing valid V2 state wins; invalid V2 state remains hard deny and is never replaced from V1.

Mechanical conversion and V1 runtime fallback were rejected because V1 authorized shell command text while V2 binds resolved executable identity and canonical argv. Conversion could widen narrow text rules into broad command-host grants, while dual evaluators would preserve parallel authorization paths.

Validation

  • .\build.ps1
  • dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --no-restore
    • 3,249 passed, 32 skipped, 0 failed
  • dotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --no-restore
    • 1,954 passed, 0 failed
  • dotnet test .\tests\OpenClaw.WinNode.Cli.Tests\OpenClaw.WinNode.Cli.Tests.csproj --no-restore
    • 126 passed, 0 failed
  • dotnet test .\tests\OpenClaw.SetupEngine.Tests\OpenClaw.SetupEngine.Tests.csproj --no-restore
    • 697 passed, 0 failed
  • dotnet test .\tests\OpenClaw.Tray.IntegrationTests\OpenClaw.Tray.IntegrationTests.csproj --no-restore
    • 19 passed, 0 failed
  • .\scripts\validate-mxc-e2e.ps1
    • 2 passed, 0 failed, 0 skipped
  • PowerShell parser validation passed for both modified uninstall scripts.

Real behavior proof

Gateway to Windows node to MXC

Canonical argv:

["cmd.exe","/d","/s","/c","echo OPENCLAW_GATEWAY_SYSTEM_RUN_MXC_SOURCE_READY && echo OPENCLAW_GATEWAY_SYSTEM_RUN_MXC_DENIED_PAYLOAD > \"C:\\Users\\...\\AppData\\Roaming\\OpenClawE2E\\...\\mxc-denied-write-....txt\""]

Observed:

SOURCE_READY: present
stderr: Access is denied.
exitCode: 1
fileExists: False
executor: mxc-direct-appc
contained: True
containment: mxc

The companion execution proof returned the expected marker with exit code 0 through the same contained path.

Local MCP

winnode --list-tools advertised:

system.run: command (string[] argv, required)

Canonical invocation returned:

{
  "stdout": "OPENCLAW_LOCAL_MCP_CANONICAL_ARGV_OK",
  "stderr": "",
  "exitCode": 0,
  "timedOut": false,
  "success": true
}

Runtime logs confirmed path=v2, decision=Allow, contained=True, and containment=mxc.

Upgrade characterization

Automated upgrade tests cover:

  • V1 allow rule with no V2: V1 unchanged, unattended deny, attended prompt/Allow once.
  • V1 deny rule with no V2: V1 unchanged, unattended deny, attended decision explicitly owns any override.
  • Malformed V1: never parsed, remains unchanged, fresh V2 behavior applies.
  • Existing valid V2 plus V1: V2 wins unchanged.
  • Invalid V2 plus V1: hard deny; neither file is overwritten.

Adversarial review

Claude Opus 4.8 and GPT-5.6 Sol independently reviewed the complete diff through three rounds with cross-model challenge and re-review after fixes.

  • Final Opus confidence: 95/100
  • Final Sol confidence: 96/100
  • Unresolved HIGH/MEDIUM findings: none
  • Remaining actionable findings: none

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P1 Urgent regression or broken agent/channel workflow affecting real users now. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 24, 2026
@clawsweeper

clawsweeper Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed July 29, 2026, 1:56 PM ET / 17:56 UTC.

ClawSweeper review

What this changes

This PR makes Windows node command execution use a V2 approval system that authorizes canonical argv, stores executable-path rules, prompts locally, and runs approved argv through local or MXC runners.

Merge readiness

⚠️ Ready for maintainer review - 4 items remain

Keep this PR open for maintainer approval rather than automated cleanup. The latest head appears to address the prior concrete redaction and remote-policy findings, but it deliberately changes the external system.run contract and retires persisted V1 approvals, so the compatibility decision still needs an explicit owner. Likely related people: shanselman (recent security and compatibility reviewer, medium confidence) and AlexAlves87 (original V2 approval-dialog contributor, medium confidence).

Priority: P1
Reviewed head: 7b6240fec83f0a44aa1d0db7c8286161da59e9d1
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) Strong real-path proof and extensive focused coverage support the implementation, while the deliberately breaking upgrade contract still needs maintainer acceptance.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The PR body reports current-head live gateway-to-Windows-node MXC execution and containment-denial output plus local MCP canonical-argv output; redact private paths, tokens, and endpoints in any future shared artifacts.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The PR body reports current-head live gateway-to-Windows-node MXC execution and containment-denial output plus local MCP canonical-argv output; redact private paths, tokens, and endpoints in any future shared artifacts.
Evidence reviewed 5 items Latest PR head includes targeted redaction follow-up: The current head is 7b6240fec83f0a44aa1d0db7c8286161da59e9d1 (fix: harden approval redaction boundaries). The supplied diff adds prompt-handler regressions that keep benign heuristic matches approvable while denying unsafe concealment, directly addressing the prior review concern about broad Redacted => Deny behavior.
Remote policy parsing is fail-closed: The V2 store configures JsonStringEnumConverter with integer enum values disabled, and the PR discussion records focused monotonicity coverage after the earlier undefined-enum bypass report.
Breaking caller migration is explicit: The V2 validator rejects string-form commands with command-array-required; the CLI skill documents the before-and-after argv migration for raw MCP, direct invocation, plugins, and winnode callers.
Findings None None.
Security None None.

How this fits together

Windows-node system.run accepts requests from the gateway, local MCP, CLI, and plugins, then applies a local approval policy before selecting a local or MXC execution runner. This PR replaces command-text policy matching with executable identity and canonical argv, affecting approval prompts, stored policy, and external callers of the node API.

flowchart LR
  A[Gateway, MCP, CLI, plugins] --> B[system.run canonical argv request]
  B --> C[V2 input and executable resolution]
  C --> D[Local approval policy and prompt]
  D --> E{Approved and still current?}
  E -->|No| F[Typed deny result]
  E -->|Yes| G[Local or MXC runner]
  G --> H[Command result and audit telemetry]
Loading

Decision needed

Question Recommendation
Should Windows node V2 ship as the documented breaking cutover that rejects low-level string commands and retires V1 persisted approvals without runtime migration? Approve the documented V2 cutover: Accept canonical argv as the required low-level contract and the unattended V1 deny behavior, with the existing migration documentation carried into release communication.

Why: The implementation intentionally avoids unsafe conversion and dual evaluators, but accepting the resulting upgrade behavior is a product and release-contract choice rather than a mechanical code-review decision.

Before merge

  • Resolve merge risk (P1) - Existing raw MCP, direct node.invoke, plugin, and winnode integrations that send string-form commands or non-empty custom environment variables will fail until migrated to canonical argv.
  • Resolve merge risk (P1) - Existing unattended installations with V1 exec-policy.json allow rules will stop executing those commands after upgrade; V1 rules remain untouched but are intentionally no longer evaluated.
  • Resolve merge risk (P1) - This is a large authorization-boundary rewrite across 81 files, so release acceptance should include explicit confirmation that the documented breaking upgrade behavior is intended.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Authorization rewrite scope 81 files, 6,520 added, 6,892 removed The PR replaces policy persistence, prompting, command validation, runner transport, UI, docs, and regression coverage in one merge-sensitive change.
Reported focused validation 6 test suites plus 2 MXC E2E proofs The PR body reports shared, tray, CLI, setup, integration, and real contained-command validation for the changed execution boundary.

Merge-risk options

Maintainer options:

  1. Approve the explicit upgrade contract (recommended)
    Merge after a maintainer records that string-form callers and V1 unattended approvals may break under the documented V2 cutover.
  2. Add a compatibility transition
    Preserve a narrow legacy boundary or stage the cutover so existing direct callers have a supported migration window.
  3. Pause pending release direction
    Do not merge until the release owner chooses the intended support and versioning posture for V1-policy users.

Technical review

Best possible solution:

Land a single authoritative argv-based approval path only after a maintainer explicitly accepts the documented API and V1-policy cutover, with release-facing migration guidance for affected low-level callers and unattended deployments.

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

Not applicable as a standalone bug report. The PR body provides concrete live gateway-to-Windows-node MXC and local MCP execution evidence, while the remaining question is product acceptance of the upgrade contract.

Is this the best way to solve the issue?

Unclear. A single canonical-argv authorization path is maintainable and avoids unsafe V1 command-text conversion, but maintainers must decide whether the intentional caller and upgrade break is acceptable for this release.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 80f35d074876.

Labels

Label justifications:

  • P1: This changes the command-execution authorization boundary and can disrupt existing Windows-node automation after upgrade.
  • merge-risk: 🚨 compatibility: String-form low-level calls and persisted V1 unattended allow rules intentionally stop working after the V2 cutover.
  • merge-risk: 🚨 security-boundary: The patch becomes the authoritative local authorization and approval path for arbitrary Windows node command execution.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body reports current-head live gateway-to-Windows-node MXC execution and containment-denial output plus local MCP canonical-argv output; redact private paths, tokens, and endpoints in any future shared artifacts.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body reports current-head live gateway-to-Windows-node MXC execution and containment-denial output plus local MCP canonical-argv output; redact private paths, tokens, and endpoints in any future shared artifacts.

Evidence

What I checked:

  • Latest PR head includes targeted redaction follow-up: The current head is 7b6240fec83f0a44aa1d0db7c8286161da59e9d1 (fix: harden approval redaction boundaries). The supplied diff adds prompt-handler regressions that keep benign heuristic matches approvable while denying unsafe concealment, directly addressing the prior review concern about broad Redacted => Deny behavior. (tests/OpenClaw.Shared.Tests/ExecApprovalV2UiPromptHandlerTests.cs:95, 7b6240fec83f)
  • Remote policy parsing is fail-closed: The V2 store configures JsonStringEnumConverter with integer enum values disabled, and the PR discussion records focused monotonicity coverage after the earlier undefined-enum bypass report. (src/OpenClaw.Shared/ExecApprovals/ExecApprovalsStore.cs:22, 7b6240fec83f)
  • Breaking caller migration is explicit: The V2 validator rejects string-form commands with command-array-required; the CLI skill documents the before-and-after argv migration for raw MCP, direct invocation, plugins, and winnode callers. (src/OpenClaw.WinNode.Cli/skill.md:90, 7b6240fec83f)
  • V2 dialog lineage: The merged V2 prompt-dialog baseline came from commit 76f4d52c3b5e512db3fb4a6856a665bd336009df; this PR extends that established local-approval surface into the authoritative execution path. (src/OpenClaw.Tray.WinUI/Dialogs/ExecApprovalDialog.cs:50, 76f4d52c3b5e)
  • Repository validation and proof policy applied: The repository policy requires the shared and tray test suites plus MXC E2E for this subsystem. The PR body reports those required validations, WinNode and setup suites, and live gateway-to-node MXC proof; review could not independently rerun them in the read-only environment. (AGENTS.md:1, 7b6240fec83f)

Likely related people:

  • shanselman: Their review comments identified the remote policy monotonicity and approval-display security requirements, then confirmed the first set of fixes and reviewed the later redaction edge cases. (role: recent security and compatibility reviewer; confidence: medium; files: src/OpenClaw.Shared/ExecApprovals/ExecApprovalsStore.cs, src/OpenClaw.Shared/ExecApprovals/ExecApprovalV2UiPromptHandler.cs)
  • AlexAlves87: Their merged dialog work established the local approval UI and sanitizer foundation that this PR now makes authoritative for command execution. (role: original V2 approval-dialog contributor; confidence: medium; commits: 76f4d52c3b5e; files: src/OpenClaw.Tray.WinUI/Dialogs/ExecApprovalDialog.cs)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Obtain explicit maintainer approval for the argv-only and V1-policy retirement contract before merge.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (5 earlier review cycles)
  • reviewed 2026-07-24T18:47:39.372Z sha 44c7a96 :: found issues before merge. :: [P1] Preserve configured approvals across upgrades
  • reviewed 2026-07-27T06:59:41.984Z sha f7e2ae0 :: found issues before merge. :: [P1] Preserve existing approval constraints across upgrades | [P1] Keep compatibility for string-form system.run callers
  • reviewed 2026-07-27T07:25:22.321Z sha c444067 :: found issues before merge. :: [P1] Preserve the supported string-form system.run contract | [P1] Preserve or explicitly migrate existing approval constraints
  • reviewed 2026-07-28T06:03:09.274Z sha 25660b0 :: found issues before merge. :: [P1] Preserve the supported string-form system.run contract
  • reviewed 2026-07-29T12:43:34.889Z sha 3f44199 :: needs maintainer review before merge. :: none

@bkudiess

Copy link
Copy Markdown
Collaborator Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 24, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@bkudiess

Copy link
Copy Markdown
Collaborator Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 27, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bkudiess
bkudiess force-pushed the bkudiess-v2-exec-approvals-pr branch from f7e2ae0 to c444067 Compare July 27, 2026 07:13
@bkudiess
bkudiess marked this pull request as ready for review July 27, 2026 07:16
@shanselman

Copy link
Copy Markdown
Collaborator

I am holding this below the repository's 90% merge-confidence bar after independent Opus and Codex reviews of the current head c4440674. Both reviewers confirmed the core V2 authorization path is fail-closed, but three unresolved release/security-contract issues remain:

  1. String-form system.run compatibility is removed. Existing external callers using a string command (or safe custom env) now receive a hard error. Please preserve a boundary compatibility shim or document and gate the versioned contract break with migration guidance.
  2. Persisted V1 allow/deny policy is ignored on upgrade. Existing unattended allows stop working, and prior explicit denies lose their configured intent. Since V1 text rules cannot safely become V2 resolved identities, please add a visible reapproval/migration notice or obtain explicit product sign-off for the breaking upgrade behavior.
  3. Remote system.execApprovals.set can weaken prompt semantics for existing grants. ValidateExecApprovalsDelta prevents new allowlist patterns but allows ask: always to become on-miss/off with the same patterns, converting confirm-every-time entries into unattended execution. Please enforce immutable-or-more-restrictive ask, askFallback, and security changes and add focused tests.

The first two may be deliberate product decisions, but they need explicit release handling. The third is a concrete authorization-policy gap that should be fixed before merge.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bkudiess

Copy link
Copy Markdown
Collaborator Author

@shanselman Thanks for the review. The concrete remote-policy weakening gap is fixed on the updated head:

  • system.execApprovals.set now compares effective defaults, wildcard, and every agent scope.
  • Remote updates may preserve or tighten security, ask, askFallback, and autoAllowSkills, but cannot weaken them.
  • Existing locally-established Full values can round-trip while another axis tightens; lower policies cannot introduce Full.
  • Focused monotonicity tests cover all four weakening axes, tighter updates, lower-to-Full rejection, and Full-preserving tightening.

Explicit product/release decision for the other two items:

  1. Low-level system.run is intentionally V2 argv-only. The normal gateway exec host=node flow already emits canonical Windows argv. Raw MCP, direct node.invoke, plugin, and winnode callers must migrate from string+shell to explicit argv. Runtime now returns command-array-required, and README, architecture docs, and winnode skill include exact before/after migration examples. Non-empty custom env remains intentionally unsupported until it can be identity-bound and displayed safely.
  2. Windows V1 policy is intentionally retired without migration. V1 command-text rules remain byte-for-byte untouched but are not evaluated or converted. Fresh valid V2 uses empty allowlist + prompt-on-miss + unattended deny. Upgrade characterization covers V1 allow, deny, malformed, valid-V2 precedence, and invalid-V2 hard deny. This break is accepted to avoid unsafe semantic conversion and parallel authorization engines, matching the macOS cutover approach.

Current validation: build green; Shared 3,249 passed / 32 skipped; Tray 1,954; CLI 126; SetupEngine 697; Tray Integration 19; MXC E2E 2/2 with true contained Access denied proof. Opus and Sol found no remaining actionable issues at 95% / 96% confidence.

Please reconsider the merge-confidence gate on the updated head.

@bkudiess

Copy link
Copy Markdown
Collaborator Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@shanselman

Copy link
Copy Markdown
Collaborator

I re-reviewed current head b6a83b70 against current main. The earlier remote monotonicity issue is fixed: the defaults, wildcard, and union of agent scopes are compared across security, ask, askFallback, and autoAllowSkills, and the focused tests cover the intended transitions. The argv-only and V1 retirement decisions are now explicit and documented.

Two new blockers remain:

  1. Undefined numeric enum values can bypass remote policy monotonicity and runtime evaluation. ExecApprovalsStore.JsonOptions uses JsonStringEnumConverter with its default allowIntegerValues: true, and neither deserialization nor ValidateExecApprovalsDelta checks Enum.IsDefined. A remote replacement containing values such as security: -1 and ask: 99 passes the ordering checks as if it were more restrictive. At runtime those values match none of the Deny, Allowlist, Always, or OnMiss branches in ExecApprovalEvaluator, so evaluation falls through to Allow. Please reject integer enum input and explicitly validate every policy enum in defaults, wildcard, and agent scopes, with adversarial tests through system.execApprovals.set.

  2. The approval redactor can hide arbitrary command payloads from the user. The PEM pattern matches an unbounded attacker-controlled span between BEGIN ... PRIVATE KEY and END ... PRIVATE KEY, and RedactPemBlock replaces the entire matched span. An agent can put destructive shell text between fake markers so the approval dialog shows only *** or the marker lines plus …redacted…. The prompt correctly denies truncated/oversized commands because hidden text is not reviewable, but it does not deny or visibly flag redacted commands. Please make redaction status explicit and fail closed or present an unavoidable warning, and constrain the PEM matcher so it cannot serve as a general-purpose hide-text primitive.

Validation on the current-main merged state:

  • ./build.ps1: passed
  • Shared: 3,249 passed, 32 skipped
  • Tray: 1,955 passed
  • WinNode CLI: 126 passed
  • SetupEngine: 697 passed
  • Tray Integration: 19 skipped because its live-app gate was not enabled

Recommendation: hold until both blockers have focused regression tests. Confidence: 96% on the numeric bypass and 93% on the redaction exploit path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jul 29, 2026
@shanselman

Copy link
Copy Markdown
Collaborator

Re-review at 3f44199e: the two original blockers are fixed. Numeric enum policy values now fail closed, and fake PEM markers can no longer conceal arbitrary shell text in an approvable dialog.

I am still holding this head because the replacement PEM pattern introduces two verified secret-display regressions:

  1. Escaped-newline PEM values are no longer redacted. echo -----BEGIN PRIVATE KEY-----\nQUJDREVGR0hJSktMTU5PUA==\n-----END PRIVATE KEY----- returns Redacted=false and preserves the full payload.
  2. A valid PEM block whose final base64 line is short and padded is no longer redacted. A body ending with Ag== returns Redacted=false and preserves the full payload.

The pattern currently requires literal line breaks and at least four non-padding base64 characters on every line. It should accept literal or escaped line separators where those serialized forms are supported, and allow a valid short padded final line. Please add regressions for both cases.

There is also a concrete behavior regression in the new Redacted => Deny gate: heuristic matches deny before showing the dialog even when no secret value is present. For example, both ...?key=$GOOGLE_KEY and GitHub search ...?code=abc return Redacted=true, so the owner cannot approve them. The concealment fix needs a narrower status than "any masking occurred", or at minimum a distinct actionable denial result. Do not remove the deny gate without replacing its concealment invariant.

Focused exec-approval tests pass: 273/273. Independent Codex review found the original blockers closed; Opus found the cases above, and I reproduced all four inputs against the current-main merge. Hold confidence: 95%.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P1 Urgent regression or broken agent/channel workflow affecting real users now. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants