[codex] Bind exec approval trust to realpaths#82825
Conversation
|
Codex review: found issues before merge. Summary Reproducibility: yes. at source level. Current main computes Real behavior proof Next step before merge Security Review findings
Review detailsBest possible solution: Land a revised realpath-canonicalization change that keeps interpreter and inline-eval detection keyed to executable identity and only trusts derived safe-bin target dirs after the same writable-dir handling as explicit trust. Do we have a high-confidence way to reproduce the issue? Yes, at source level. Current main computes Is this the best way to solve the issue? No. Realpath-bound trust is the right direction, but this PR is not safe to merge until it preserves interpreter/inline-eval guards and handles writable derived safe-bin target dirs. Full review comments:
Overall correctness: patch is incorrect Security concerns:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against c4f20b656eac. |
92384ce to
caaa942
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: caaa942845
ℹ️ 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".
| const patternMatches = hasPathSelector(pattern) | ||
| ? matchesExecAllowlistPattern(pattern, resolvedPath) | ||
| ? matchesExecAllowlistPattern(pattern, trustPath) | ||
| : pattern !== "*" && matchesExecutableBasenamePattern(pattern, resolution); |
There was a problem hiding this comment.
Preserve compatibility for existing path allowlist entries
Matching path-shaped allowlist patterns only against trustPath means existing entries saved as symlink paths (for example /opt/homebrew/bin/rg) will stop matching immediately after this upgrade, even when the binary target has not changed. In environments that already persisted those patterns via prior allow-always decisions or manual edits, this becomes a behavior regression (unexpected allowlist miss prompts) rather than a security hardening-only change. Consider matching both candidate and trust paths during a transition window, or migrating stored path patterns to their current realpaths when loading approvals.
Useful? React with 👍 / 👎.
47aebe5 to
856c5a3
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 856c5a3f0f
ℹ️ 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".
| const candidatePath = resolveExecutionTargetTrustPath(segment.resolution, params.cwd); | ||
| if (!candidatePath) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Keep interpreter guard off trust-path basename in allow-always
collectAllowAlwaysPatterns now feeds the trust realpath into isInterpreterLikeAllowlistPattern, which can hide interpreter identity when symlinks resolve to versioned binaries (for example python3 -> .../python3.12). Because isInterpreterLikeAllowlistPattern only recognizes fixed interpreter names, this path returns false and the function can persist an allow-always entry for interpreter commands that were previously blocked, reintroducing interpreter/inline-eval bypass risk on common package-manager layouts.
Useful? React with 👍 / 👎.
856c5a3 to
fd38902
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd389029f8
ℹ️ 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".
| const targetDirs = resolveTrustedSafeBinTargetDirs(entries, safeBins); | ||
| return new Set([...resolveTrustedSafeBinDirs(entries), ...targetDirs]); |
There was a problem hiding this comment.
Check writability before trusting derived safe-bin target dirs
buildTrustedSafeBinDirs now auto-adds realpath target directories for configured safe bins, but runtime warnings still only inspect explicitly configured safeBinTrustedDirs (resolveExecSafeBinRuntimePolicy calls listWritableExplicitTrustedSafeBinDirs only). This means a writable symlink target directory can become trusted without any warning, so replacing the target binary (for a permitted safe bin like jq) can bypass approval checks silently. Please gate derived target dirs behind the same writability checks (or avoid trusting them automatically) before adding them to the trusted set.
Useful? React with 👍 / 👎.
fd38902 to
d4165c6
Compare
d4165c6 to
ac12b39
Compare
Summary
Fixes #45595.
Supersedes #73543.
Verification
Real behavior proof
Behavior addressed: path-shaped exec approvals and trusted-bin decisions now bind to the executable realpath instead of the mutable symlink path.
Real environment tested: local OpenClaw checkout at ac12b39 using production exec approval modules via Node/tsx, with real temp executable files and symlinks on macOS.
Exact steps or command run after this patch: ran a Node/tsx OpenClaw production-module probe that created executable safe-bin symlinks, evaluated allowlist matching, retargeted the symlink, and re-evaluated safe-bin trust.
Evidence after fix: terminal output from the real production-module probe:
Observed result after fix: the symlink-path allowlist did not match, the realpath allowlist did match, old executable targets stopped being trusted after symlink retargeting, the new target was trusted, and a non-executable safe-bin symlink did not expand trust to a sibling executable directory.
What was not tested: native approval UI button flow; this proof covers the runtime policy decision path before UI delivery.