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
Node's recursive mkdirSyncfollows a symlink at the final component (no lstat). If .worktrees is a symlink, path.join resolves through it, and git worktree add populates the symlink target with a full git checkout.
Attack
An attacker who can place one symlink at <repoRoot>/.worktrees — via a crafted/tarballed repo that ships .worktrees → ~/.ssh, a co-resident user on a shared dev box, or a prior malicious Codex run doing rm -rf .worktrees && ln -s ~/.config .worktrees — causes the next rescue's worktree (the Codex workspace-write root) to be created in ~/.ssh/, ~/.config/, ~/Library/LaunchAgents/, etc. That is sandbox escape + a persistence/credential-injection primitive.
Reproduced end-to-end:.worktrees → /tmp/attacker-dest produced /tmp/attacker-dest/codex-FAKE/ populated with HEAD content; the ~/.ssh variant also reproduced (then cleaned up).
Severity
CRITICAL once createWorktreeSession is wired into the rescue flow (it currently has no production callers — #12 landed the library layer only). Not a live exploitable surface today, but must be closed before the --worktree flag reaches the CLI.
Fix
Before mkdirSync(worktreesDir), lstatSync(worktreesDir) and bail (or remove the offending symlink) if it is a symlink. Better: reject symlinked components in the whole .worktrees path and verify the resolved realpath is contained within repoRoot. Or create worktrees under an app-owned mkdtemp dir rather than inside the repo.
Activity
fix(security): refuse symlink at .worktrees before creating a worktree (
fix(security): eliminate info/exclude write — use in-repo .worktrees/…
fix(security): eliminate info/exclude write — use in-repo .worktrees/…