feat(exec): add normalized auto mode#70543
Conversation
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟠 Legacy execSecurity/execAsk overrides can be silently bypassed by persisted execMode
Description
Impact:
Vulnerable code: if (params.sessionEntry?.execMode) {
return params.sessionEntry.execMode as ExecMode;
}This occurs before checking legacy overrides, and later:
RecommendationMake legacy policy fields take precedence over Option A (prefer legacy overrides): function resolveLayeredExecMode({ sessionEntry, agentExec, globalExec }: Params): ExecMode | undefined {
// If legacy knobs are set, ignore mode (forces resolveExecModePolicy to use security/ask)
if (sessionEntry?.execSecurity !== undefined || sessionEntry?.execAsk !== undefined) {
return undefined;
}
if (sessionEntry?.execMode) return sessionEntry.execMode as ExecMode;
if (agentExec?.security !== undefined || agentExec?.ask !== undefined) return undefined;
if (agentExec?.mode) return agentExec.mode;
return globalExec?.mode;
}Option B (reject mixed settings): when applying patches/config, if Also apply the same precedence rule anywhere else Analyzed PR: #70543 at commit Last updated on: 2026-04-23T08:29:27Z |
Greptile SummaryThis PR introduces a unified
Confidence Score: 4/5Safe to merge after resolving the One P1 security defect: src/infra/exec-auto-review.ts —
|
| "ls", | ||
| "pwd", | ||
| "rg", | ||
| "sed", |
There was a problem hiding this comment.
sed is not read-only — -i flag enables in-place file mutation
sed is included in READ_ONLY_BINARIES, but sed -i 's/old/new/' config.txt silently rewrites files on disk. Because commandLooksCompound and hasDangerousToken both miss it (no compound operator, and sed is absent from the dangerous-token regex), isReadOnlyCommand returns true for any sed invocation and the auto-reviewer returns allow-once (risk: "low"), bypassing human review for a file-mutating command.
The git entry is correctly guarded via a subcommand allowlist; sed needs equivalent argv inspection (e.g. reject if any arg matches -i or --in-place) or should be removed from the set until that guard is added.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/exec-auto-review.ts
Line: 57
Comment:
**`sed` is not read-only — `-i` flag enables in-place file mutation**
`sed` is included in `READ_ONLY_BINARIES`, but `sed -i 's/old/new/' config.txt` silently rewrites files on disk. Because `commandLooksCompound` and `hasDangerousToken` both miss it (no compound operator, and `sed` is absent from the dangerous-token regex), `isReadOnlyCommand` returns `true` for any `sed` invocation and the auto-reviewer returns `allow-once` (risk: "low"), bypassing human review for a file-mutating command.
The `git` entry is correctly guarded via a subcommand allowlist; `sed` needs equivalent argv inspection (e.g. reject if any arg matches `-i` or `--in-place`) or should be removed from the set until that guard is added.
How can I resolve this? If you propose a fix, please make it concise.| ): Promise<SystemRunPolicyPhase | null> { | ||
| const cfg = await loadSystemRunConfig(opts); | ||
| const agentExec = resolveAgentExecConfig(cfg, parsed.agentId); | ||
| const configuredSecurity = opts.resolveExecSecurity( | ||
| agentExec?.security ?? cfg.tools?.exec?.security, | ||
| ); | ||
| const configuredAsk = opts.resolveExecAsk(agentExec?.ask ?? cfg.tools?.exec?.ask); | ||
| const globalExec = cfg.tools?.exec; | ||
| const mode = | ||
| agentExec?.mode ?? | ||
| (agentExec?.security !== undefined || agentExec?.ask !== undefined | ||
| ? undefined | ||
| : globalExec?.mode); | ||
| const modePolicy = resolveExecModePolicy({ | ||
| mode, | ||
| security: opts.resolveExecSecurity(agentExec?.security ?? globalExec?.security), | ||
| ask: opts.resolveExecAsk(agentExec?.ask ?? globalExec?.ask), | ||
| }); | ||
| const configuredSecurity = modePolicy.security; | ||
| const configuredAsk = modePolicy.ask; | ||
| const approvals = resolveExecApprovals(parsed.agentId, { | ||
| security: configuredSecurity, | ||
| ask: configuredAsk, |
There was a problem hiding this comment.
modePolicy.autoReview computed but never consumed
resolveExecModePolicy returns an autoReview boolean, but only modePolicy.security and modePolicy.ask are forwarded from evaluateSystemRunPolicyPhase. Setting tools.exec.mode="auto" on the embedded/pi-runner path will correctly adjust security and ask values, but the auto-reviewer will never fire for commands that miss the allowlist on this host. If this is an intentional scope boundary for this PR, a comment documenting the gap would help future contributors.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/node-host/invoke-system-run.ts
Line: 373-391
Comment:
**`modePolicy.autoReview` computed but never consumed**
`resolveExecModePolicy` returns an `autoReview` boolean, but only `modePolicy.security` and `modePolicy.ask` are forwarded from `evaluateSystemRunPolicyPhase`. Setting `tools.exec.mode="auto"` on the embedded/pi-runner path will correctly adjust security and ask values, but the auto-reviewer will never fire for commands that miss the allowlist on this host. If this is an intentional scope boundary for this PR, a comment documenting the gap would help future contributors.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b119e64fb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "ls", | ||
| "pwd", | ||
| "rg", | ||
| "sed", |
There was a problem hiding this comment.
Remove
sed from read-only auto-review allowlist
The auto reviewer currently classifies every sed invocation as read-only, but sed supports in-place writes (for example, -i) without needing shell composition tokens. In tools.exec.mode="auto", an allowlist miss can therefore be auto-approved even when the command mutates files, which violates the intended “read-only inspection command” boundary and skips human approval for state-changing operations.
Useful? React with 👍 / 👎.
| ]); | ||
|
|
||
| const GIT_READ_ONLY_SUBCOMMANDS = new Set([ | ||
| "branch", |
There was a problem hiding this comment.
Validate
git branch arguments before auto-approving
The reviewer marks git branch as read-only based only on subcommand name, but git branch mutates repository refs when given create/delete flags or branch names (for example, git branch feature-x, git branch -D old). With mode=auto, these approval misses can be auto-approved as low risk and execute without operator confirmation, allowing unintended repo mutations.
Useful? React with 👍 / 👎.
7b119e6 to
05b0336
Compare
|
Codex review: needs maintainer review before merge. Reviewed May 29, 2026, 10:03 AM ET / 14:03 UTC. Summary Reproducibility: not applicable. this is a feature/config PR, not a bug report. The behavior is source-reviewable in the PR head and supported by CI/release validation evidence in the PR body. Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land this only after maintainers explicitly accept the exec auto-review security boundary and the new public config, SDK, and protocol contracts, with current-head checks green. Do we have a high-confidence way to reproduce the issue? Not applicable: this is a feature/config PR, not a bug report. The behavior is source-reviewable in the PR head and supported by CI/release validation evidence in the PR body. Is this the best way to solve the issue? Unclear as a product/security decision: the implementation path is coherent, but maintainers still need to accept the normalized config contract and model-backed exec approval boundary before merge. AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against af3e354ff8c8. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
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. How this review workflow works
|
05b0336 to
1d45724
Compare
|
ClawSweeper PR egg ✨ Hatched: 🌱 uncommon Gilded Branchling Hatch commandComment Hatchability rules:
Rarity: 🌱 uncommon. What is this egg doing here?
|
Dependency Changes DetectedThis PR changes dependency-related files. Maintainers should confirm these changes are intentional. Changed files:
Maintainer follow-up:
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
Completed 2 |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Dependency graph guard clearedThis PR no longer has blocked dependency graph changes. A future dependency graph change requires a fresh
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
|
Merged via rebase onto Verification before merge: Observed result: GitHub checks on the merged PR head The landed PR range contains 19 commits, from |
Summary
Adds normalized
tools.exec.modesupport for host exec policy and mapstools.exec.mode: "auto"to Guardian-reviewed Codex app-server execution.The native
autopath uses deterministic allowlist/safe-bin matches directly. On approval misses, it asks the model-backed exec reviewer for a one-shot allow decision. Anything else routes to human approval.Scope Boundary
Included:
tools.exec.modevalues:deny,allowlist,ask,auto,full.autoto Guardian/auto_reviewapprovals.Not included:
execMode.execOverrides.mode./exec mode=...directive surface.Behavior Notes
allow-once, OpenClaw records and resolves a suppressed one-shot approval.ask, malformed output, or anything unsupported, OpenClaw routes to human approval.askFallback=fulldoes not execute the command.system.runauto-review requires the preparedsystemRunPlanbefore approved scoped execution.execstill works when globaltools.exec.mode: "auto"is configured andtools.exec.hoststays on the defaultautoroute.security=full, ask=on-missstays full execution behavior; onlyfull/alwaysprompts.Verification
Release-candidate proof was completed on commit
7f39268bed3920270c02d3c72ffa10ee22138802.system.run, gateway approval routing, sandbox exec fallback, config/schema behavior, Codex app-server policy mapping, SDK export, doctor/security warnings, and the release-matrix regressions found while validating the PR.26626309934completed successfully.26626597167, Plugin Prerelease26626597790, OpenClaw Release Checks26626596624, OpenClaw Performance26626596215, and NPM Telegram Beta E2E26626763921all completed successfully.Real Behavior Proof
Behavior addressed: Native OpenClaw
tools.exec.mode: "auto"and Codex app-server Guardian-reviewed approvals now share one normalized config surface.Real environment tested: OpenClaw release-candidate validation in GitHub Actions on commit
7f39268bed3920270c02d3c72ffa10ee22138802, including normal CI, plugin prerelease, live provider/release checks, Docker/package acceptance, cross-platform release checks, product performance evidence, and Telegram package E2E. Focused local regression coverage also passed before the release-candidate matrix was dispatched.Exact steps or command run after this patch: Ran final structured auto-review to zero accepted/actionable findings, then ran the full release validation matrix to completion on the PR head SHA.
Evidence after fix: Full Release Validation run
26626309934completed successfully. Its child workflows for CI, Plugin Prerelease, OpenClaw Release Checks, OpenClaw Performance, and NPM Telegram Beta E2E all completed successfully.Observed result after fix: Auto exec mode policy normalization, auto-review allow paths, auto-review-to-human paths, fallback-full blocking, sandbox exec with global auto mode, Codex app-server policy mapping, node
system.runapproval-plan enforcement, security-suppression human review, legacyfull/on-missreporting, config/schema behavior, and release-candidate live/Docker/package/Telegram paths are covered by passing proof.What was not tested: No intentional release-candidate proof gaps remain from this validation pass. Manual exploratory UI review was not separately performed beyond the automated release/live matrix.
Compatibility / Migration
Existing
tools.exec.securityandtools.exec.askcontinue to work. New configs should prefertools.exec.modefor the normalized policy. Explicit lower-scope legacy policy values still take precedence where they already apply.