openai / openai/codex-plugin-cc

app-server-broker silently disables all git hooks when started in a git worktree

Open
#697 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
33.3k
Forks
2.3k
PR merge metrics
No merged PRs in 30d

Description

Summary

Starting the Codex app-server broker with --cwd pointing at a linked git worktree writes two values into the repository's shared .git/config within ~25 seconds:

core.bare      = true
core.hooksPath = .no-hooks

.no-hooks does not exist. Git therefore silently skips every hook for the whole repository — not just for the Codex session, and not just in that worktree. core.bare = true additionally makes the main checkout and every linked worktree unusable (fatal: this operation must be run in a work tree).

Nothing warns the user. A push that skips all pre-push checks looks exactly like a normal push.

Environment
Plugin codex 1.0.6 (marketplace openai-codex)
Codex CLI codex-cli 0.147.0
git 2.55.0
node v24.19.0
OS macOS 26.6.2, arm64

The repository uses extensions.worktreeConfig = true and husky (core.hooksPath = .husky/_).

Reproduction
# in any git repo that has at least one commit
REPO=$(pwd)

git config core.bare            # -> false
git config core.hooksPath       # -> e.g. .husky/_

git worktree add -b probe /tmp/probe-wt HEAD

node <plugin>/scripts/app-server-broker.mjs serve \
  --endpoint "unix:$(mktemp -d)/b.sock" \
  --cwd /tmp/probe-wt \
  --pid-file "$(mktemp -d)/b.pid" &

sleep 30

git config core.bare            # -> true      (was false)
git config core.hooksPath       # -> .no-hooks (was .husky/_)
Expected

The broker should not persist configuration into the user's shared repository
config. If it needs to suppress hooks for its own git invocations, that belongs
in the invocation scope, for example git -c core.hooksPath= … or the
GIT_CONFIG_COUNT / GIT_CONFIG_KEY_* environment, not in .git/config.

Actual

Both values are written persistently to the shared config and are never
restored
, including after the session ends.

Key discriminator
--cwd points at Result
a linked worktree corrupted after ~25 s (reproduced repeatedly)
the main checkout clean after 45 s of observation

So the trigger is specific to linked worktrees. A plausible mechanism: in a
linked worktree .git is a file pointing at .git/worktrees/<name>. Something
in the startup path appears to mis-detect that as a bare repository and then
persists both core.bare and the hook suppression into the common config
shared by every worktree.

Impact

This is a security issue, not only an annoyance:

  • All local hooks are disabled repository-wide, for every worktree and the
    main checkout, not just for the Codex session.
  • Every locally enforced pre-push check is removed at once, whatever a given
    project runs there.
  • The failure is invisible. Git does not warn about a core.hooksPath
    that points nowhere, so pushes simply proceed with no local check having
    run and look completely normal. In our case the condition was only noticed
    because unrelated git commands started failing due to core.bare = true;
    without that side effect it could have gone unnoticed indefinitely.
  • Anyone who runs Codex sessions in worktrees is affected, and the more sessions
    are started, the more often it recurs. We measured multiple occurrences within
    a single hour.
Workaround

A watcher that restores both values. We run a small script on a launchd
WatchPaths trigger against .git/config; it repairs about one second after
each corruption. Note that putting such a repair inside a git hook does not
work: with a broken core.hooksPath no hook runs, so it cannot fire in the one
situation it is needed for.

Notes

core.bare was occasionally observed flipping back to false on its own, while
core.hooksPath stayed broken. So the two writes may come from different code
paths, and the hook suppression is the more persistent and more dangerous of the
two.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at scripts/app-server-broker.mjs and trace the startup path used by serve --cwd when the cwd is a linked worktree. Reproduce the issue with the provided git worktree commands, then verify that broker startup no longer persists core.bare or core.hooksPath in the shared config and that hooks remain usable after the session ends.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, javascript
Domain
devtools, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.