fix(security): eliminate info/exclude write (closes #16)#22
Merged
Conversation
….gitignore (closes #16) Redesign (3rd eliminate in the worktree security series, after leave-branch and core.symlinks=false). The original createWorktree wrote .worktrees/ into <gitDir>/info/exclude to keep the worktree dir out of git status. That write was the entire #16 vulnerability: if gitDir resolved outside repoRoot (separate-git-dir, crafted .git gitfile, linked worktree), the exclude write landed at an attacker-controlled location. Detection-based fixes (boundary checks) broke after 2 iterations: git introspection cannot authenticate external common-dirs — legit linked worktrees gitdir in <main>/.git/worktrees/ is indistinguishable from attack separate-git-dir via path inspection. Two independent Codex runs converged on the same conclusion: eliminate the write, don't detect. Fix: delete the entire git-dir/info/exclude block. git worktree add works WITHOUT it (the exclude was cosmetic, from openai#137 commit 4bca062). Keep .worktrees/ out of git status via an in-repo .worktrees/.gitignore containing *, written inside the already-validated worktreesDir (#14 guard ensures inside repoRoot, not a symlink). No git-dir metadata write = no write outside repoRoot = #16 dead. Regression tests: separate-git-dir repo now works (previously attack case); linked worktree works (previously broken by boundary check); external info/exclude untouched. Verified: worktree 18/18; full npm test 161 pass / 4 pre-existing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
axisrow
force-pushed
the
sec-gitdir-eliminate
branch
from
July 20, 2026 08:06
3eb9480 to
d791eab
Compare
Owner
Author
|
Cycle 1 triage: Codex HIGH (dangling .gitignore symlink redirect), Claude APPROVE (false positive — .worktrees already attacker-writable). Applied the lstat guard on .gitignore (defense-in-depth, 2 lines) in d791eab — closes both perspectives. 18/18 tests. Ready to merge. |
axisrow
added a commit
that referenced
this pull request
Jul 20, 2026
Security hardening release: leave-branch worktree cleanup (#12) + 4 security fixes (#18 symlink guard, #20 core.symlinks=false neutralize, #22 eliminate info/exclude write, #23 accumulation warn). rescue default --background (#8). test-teardown (#5). All verified with cycle-review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #16. Third eliminate-redesign in the worktree security series (after leave-branch #12 and core.symlinks=false #20).
The original createWorktree wrote .worktrees/ into /info/exclude. That write was the entire #16 vuln: if gitDir resolved outside repoRoot (separate-git-dir, gitfile, linked worktree), the write landed at attacker location. Detection-based boundary checks broke legit linked worktrees and couldn't distinguish them from attack. Eliminate the write entirely: git worktree add works without it. Use in-repo .worktrees/.gitignore instead. 18/18 tests, 161 pass / 4 pre-existing.