Skip to content

security(critical): .worktrees/ symlink traversal redirects worktree creation to arbitrary host location #14

Closed

Description

@axisrow

Security finding from the adversarial review of the worktree-isolation library layer (#12, commit 1a9eb11). Reproduced empirically.

Vulnerability

createWorktree (plugins/codex/scripts/lib/git.mjs) does:

const worktreesDir = path.join(repoRoot, ".worktrees");
fs.mkdirSync(worktreesDir, { recursive: true });
...
const worktreePath = path.join(worktreesDir, `codex-${ts}`);
gitChecked(repoRoot, ["worktree", "add", worktreePath, "-b", branch]);

Node's recursive mkdirSync follows 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.

Refs #12, #13 (umbrella), openai#135, openai#137.

Activity

  1. added 3 commits that reference this issue on Jul 19, 2026
    5a19596
    d791eab
    4063e6f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions