You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
git rev-parse --git-dir returns an absolute path whenever the repo uses --separate-git-dir, is a linked worktree, or has a .git gitfile. When the value is absolute, path.resolve(repoRoot, "/abs/path")discards repoRoot and uses the absolute path verbatim. The subsequent appendFileSync then writes .worktrees/\n at that absolute location.
Attack
A crafted repo bundled as a tarball (not git clone — clone sanitizes) ships a .git gitfile pointing at an attacker-pre-staged valid git dir elsewhere on disk (e.g. ~/.cache/evil/.git). createWorktree then appends .worktrees/\n to ~/.cache/evil/.git/info/exclude. Content is benign (.worktrees/), but the destination is attacker-controlled and there is no boundary check that gitDir is inside repoRoot — a structural gap future code could turn worse.
Reproduced
Confirmed for legit linked worktrees (--git-dir returns /private/tmp/.../main/.git/worktrees/linked-wt). Could not reach a destructive payload: git refuses a gitfile pointing at a non-git dir, so the attacker must pre-stage a valid git dir at the target. Hence MEDIUM, not HIGH.
Severity
MEDIUM today (benign-content append anywhere a valid git dir can be pre-staged); structurally a missing-boundary check.
Fix
After path.resolve, assert gitDir === repoRoot || gitDir.startsWith(repoRoot + path.sep) (with realpath normalization on both sides) and bail otherwise. Treat any --git-dir outside repoRoot as a hard error.
Update: first fix attempt (PR #21, now closed) broke legit linked worktrees. The boundary check 'gitDir inside repoRoot' rejects linked worktrees because their gitdir lives in
/.git/worktrees/, NOT in the linked worktree's path. A 'gitDir inside git-common-dir' check passes separate-git-dir (attack) because gitDir==commonDir there. Distinguishing legit-linked-worktree from attack-separate-git-dir via git path inspection is non-trivial — needs more research. Also found: info/exclude themselves could be symlinks bypassing the gitDir containment. Issue stays open until a correct fix is found.
Activity
axisrow commentedon Jul 20, 2026
Update: first fix attempt (PR #21, now closed) broke legit linked worktrees. The boundary check 'gitDir inside repoRoot' rejects linked worktrees because their gitdir lives in
/.git/worktrees/, NOT in the linked worktree's path. A 'gitDir inside git-common-dir' check passes separate-git-dir (attack) because gitDir==commonDir there. Distinguishing legit-linked-worktree from attack-separate-git-dir via git path inspection is non-trivial — needs more research. Also found: info/exclude themselves could be symlinks bypassing the gitDir containment. Issue stays open until a correct fix is found.fix(security): eliminate info/exclude write — use in-repo .worktrees/…