Curated-plugin startup sync corrupts the host repo when codex runs inside a git hook (inherited GIT_DIR) — isolation fix #29785 is in no release

Resolved 💬 4 comments Opened Jul 7, 2026 by sallyjones6 Closed Jul 10, 2026

Version: codex-cli 0.142.3 and 0.142.5 (macOS, arm64). Also affects 0.143.0-alpha.9.

Summary: The curated-plugin startup sync (core-plugins/src/startup_sync.rs) spawns git -C <cache> init / fetch --depth 1 --no-tags … +HEAD:refs/codex/curated-sync / reset --hard / clean -fdx without scrubbing repository-local git environment variables. When codex is launched from inside a git hook (e.g. a post-commit hook that runs codex exec for automated review), git has exported an absolute GIT_DIR for commits made in linked worktrees — and GIT_DIR overrides -C-based discovery in every child git process. The sync then operates on the user's repository:

  1. git init "reinitializes" the host repo with GIT_DIR set and cwd elsewhere → git guesses bare → core.bare=true is written into the shared config (breaks status/pull in the primary checkout).
  2. The fetch grafts refs/codex/curated-sync + a .git/shallow file (an openai/plugins commit) into the host repo.
  3. The reset --hard can move the user's checked-out branch to the foreign openai/plugins commit (reproduced; see below).

Notably, --sandbox read-only does not contain any of this — the sync is codex startup machinery, not sandboxed model commands.

Reproduction: in a repo, install a post-commit hook that runs codex (any prompt); commit in a linked worktree (git worktree add … && git commit …). Observe core.bare=true, refs/codex/curated-sync, and .git/shallow on the host repo. A minimal simulation (hook running the same git sequence codex spawns) shows the worktree branch hard-reset to the fetched commit.

Real-world impact: three developer repos on one machine corrupted over two days (commits from worktree hooks that spawn codex for post-commit review); the branch-reset case is especially dangerous because it's silent when the branch was already pushed.

Fix status: #29785 ("Isolate curated plugin sync Git environment", merged 2026-06-24) fixes exactly this on main — git_command() now env_removes the 16 repository-local GIT_* vars. But it is not contained in any released version: rust-v0.142.5 and rust-v0.143.0-alpha.9 both lack it. Could this be cherry-picked into the next stable release? Given the severity (silent branch reset, bypasses the read-only sandbox), it seems worth expediting.

View original on GitHub ↗

4 Comments

ChetanyaRathi · 1 month ago

Thanks for the detailed writeup and repro — the GIT_DIR inheritance angle is
clear. I'll pick this up and work on getting #29785 into a release.

mayank6091 · 1 month ago

@sallyjones6 @ChetanyaRathi Isolation is definitely important here. It would also help if the execution environment and inherited state were recorded as part of the execution metadata so unexpected workspace mutations are easier to trace back.

ChetanyaRathi · 1 month ago

This is already fixed in rust-v0.143.0 (out today). I just checked the tagged source, GIT_DIR and the other repo-local GIT_* vars are stripped via env_remove in the curated-sync git command. The repro was on 0.143.0-alpha.9, before #29785 landed; final 0.143.0 has it. Upgrading resolves this, 0.142.x backport only if that line's still maintained.

sallyjones6 · 1 month ago

Confirmed fixed as of the 0.144.0 release line: the #29785 merge commit (134646e) is an ancestor of rust-v0.144.1 (and absent from rust-v0.142.5, matching the vulnerable releases).

Verified live on codex-cli 0.144.1: with plugins force-enabled (-c features.plugins=true) and codex spawned with an inherited GIT_DIR/GIT_WORK_TREE pointing at a scratch repo, the repo stays intact — no core.bare flip, HEAD unchanged, no .git/shallow graft, no refs/codex/curated-sync ref.

Closing; the [features].plugins = false workaround is no longer needed on ≥0.144.0.