Skip to content

Guard git writes outside the bound source worktree and risky shell substitutions; release 0.2.41 (#284) - #285

Merged
lidge-jun merged 4 commits into
devfrom
codex/issue-284-source-git-guard
Oct 6, 2026
Merged

lidge-jun merged 4 commits into
devfrom
codex/issue-284-source-git-guard

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Closes #284.

On 2026-10-01 a session bound to a source worktree with cxc session source passed Markdown with inline code through a double-quoted shell argument. zsh executed the backticks, and git cherry-pick ran on the main checkout's dev instead of the bound worktree. Nothing in codexclaw objected.

Both checks below run inside the existing worktree-guard-pretool PreToolUse hook. The hook JSON is unchanged, so there is no new hook registration and no new trust hash.

  • WORKTREE-GUARD-04. When the session has a source binding, a git write (commit, cherry-pick, merge, rebase, reset, checkout/switch, am, revert, push, pull, branch -D/-f/-m) is denied if its repository is another worktree of the same repo. The deny names both roots. Unrelated repositories, read-only verbs and --abort/--quit stay allowed.
  • SHELL-SUBST-01. A backtick or $(...) substitution that the shell will run is denied if its body runs a git write or gh pr merge/close, gh issue close, gh release delete or gh repo delete. This applies with or without a binding. Single quotes and quoted-delimiter heredocs are treated as literal, and sh/bash/zsh -c payloads are scanned. Any other backtick inside double quotes gets an allow-plus-advisory.
  • cxc-dev gains DEV-SHELL-TEXT-01: generated text goes through apply_patch, files, <<'EOF' or --body-file. The worktree-guardian skill and structure/INDEX.md list the new rules.

One acceptance item differs from the issue. Codex hook payloads carry only tool_input.command; exec_command's workdir is not exposed (codex-rs unified_exec/exec_command.rs pre_tool_use_payload). The guard therefore resolves the directory from the hook cwd plus in-command cd, git -C, --git-dir and --work-tree. The allowed retry is git -C <source> ..., and the deny message says so. A tool_input.workdir field is honored if a host ever sends one. Direct git push inside a -c payload is not denied, because that also appears in legitimate ssh and remote scripts.

Validation: the new git-write-guard.test.ts (8 tests) covers the incident command, nested and -c substitutions, quoted heredocs, a real linked-worktree binding, the workdir field, and envelopes. The existing worktree-guard, hook-e2e, probe-compiled-hooks and L19 suites pass. gate.mjs passes, and the compiled dist/cli.js hook worktree-guard-pretool was smoke-tested for deny, advisory and silent allow. Locally, npm test failed only gui/test/router.test.ts, because this checkout has no node_modules (react missing).

The second commit bumps every package, the plugin manifest (0.2.41+codex.20261006130152), the lockfile and the inventory to 0.2.41, and adds the CHANGELOG entry. It touches the same 15 files as the 0.2.40 release commit, and check-versions.mjs 0.2.41, gate.mjs and inventory.mjs --check pass.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T12:58:38.625428Z 098c6e9 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 098c6e9819

ℹ️ 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".

function sourceGuard(command: string, ctx: GitSafetyContext): GitSafetyVerdict {
let segCwd = ctx.startDir;
let source: { root: string; id: RepoIdentity } | null | undefined;
for (const segment of splitSegments(command)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Split newline-delimited commands before classification

splitSegments does not split on newlines, so a normal multiline Bash request such as echo preparing\ngit -C <other-worktree> commit -m x is tokenized as one echo segment and the Git write is never examined. The same helper in riskyMutation lets $(echo preparing\ngit push) bypass SHELL-SUBST-01, so both protections can be defeated by routine multiline commands; split unquoted line breaks while preserving heredoc bodies.

Useful? React with 👍 / 👎.

Comment on lines +62 to +64
if (name === "sudo" || name === "command" || name === "builtin" || name === "env") {
rest = rest.slice(1);
continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Consume wrapper options before locating the executable

strip removes sudo or env but leaves their options and option operands at the front, so commands such as env -i git push and sudo -u root git commit leave -i or -u as the first token and parseGitCall rejects them. These commands—and the same forms inside $()—therefore execute mutations while bypassing both new guards; parse the supported wrappers' options and operands before searching for git or gh.

Useful? React with 👍 / 👎.

Comment on lines +151 to +152
while (i < command.length) {
const ch = command[i];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip shell comments when scanning substitutions

The scanner continues through unquoted shell comments, so echo ok # $(git push origin main) is denied even though Bash treats the substitution as comment text and never executes it. This can block harmless commands or generated scripts containing commented examples, contrary to the stated rule that only substitutions the shell executes are guarded; ignore comment text through the next newline.

Useful? React with 👍 / 👎.

@lidge-jun lidge-jun changed the title Guard git writes outside the bound source worktree and risky shell substitutions (#284) Guard git writes outside the bound source worktree and risky shell substitutions; release 0.2.41 (#284) Oct 6, 2026
@github-actions github-actions Bot added the chore label Oct 6, 2026
@lidge-jun
lidge-jun merged commit 225a2a7 into dev Oct 6, 2026
13 checks passed
@lidge-jun
lidge-jun deleted the codex/issue-284-source-git-guard branch October 6, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant