[BUG] bgIsolation containment check isn't realpath-canonicalized; symlinked cwd bypasses it

Status Fixed / completed
Reported on v2.1.207
Maintainer reply ✓ Yes — bcherny
Activity 3 comments · opened Jul 13, 2026 · closed Aug 17, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The bgIsolation guard's "is this path inside the shared checkout?" test is a literal prefix match against the checkout root, not realpath-resolved. In a background session, a Write/Edit/NotebookEdit addressed via a symlink-alias path bypasses bgIsolation; the canonical path to the same file is correctly blocked.

What Should Happen?

Identical enforcement for files in the same folder regardless of which equivalent path string is used (e.g. use realpath to canonicalize both the target path and the checkout root before the containment test).

Error Messages/Logs

Steps to Reproduce

Run the below script in a test environment with Claude Code 2.1.207 and no worktree.bgIsolation override, then observe that canon.txt is blocked by bgIsolation, while alias.txt is written into the checkout.

#!/bin/bash
base="$(mktemp -d)"
git init -q "$base/canonical"
ln -s "$base/canonical" "$base/alias"

cd "$base/canonical"
PROMPT="Using the Write tool, create two files: $base/canonical/canon.txt and $base/alias/alias.txt . "
PROMPT+="Do not call EnterWorktree. Report whether each Write succeeded or was blocked, then stop."
claude --bg "$PROMPT" --allowedTools "Write"
id=$(claude agents --json --all --cwd "$base/canonical" | jq -r '.[0].id')
claude attach "$id"

claude rm "$id"
rm -rf "$base/canonical/.git"
ls -alR "$base"
rm -f "$base"/canonical/{canon,alias}.txt "$base/alias"
rmdir "$base/canonical" "$base"

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.207

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Xterm

Additional Information

_No response_

View original on GitHub ↗

3 Comments

BGMLAI · 3 months ago

The canonicalization fix should happen at the authorization boundary, not only inside the background-agent feature. Normalize both the protected root and requested target with realpath, then compare path components rather than string prefixes. That also needs explicit handling for non-existent write targets: canonicalize the nearest existing parent, append the unresolved suffix, and reject if any parent is swapped during the check/use window.

A useful regression matrix would include a symlinked cwd, a symlink in the middle of the target path, ../ traversal, a sibling with the same textual prefix, and a symlink retargeted between validation and write. Disclosure: I maintain gate.cat, where protected-path policy faces the same class of canonical-path problem; this comment is architectural feedback, not a claim that a command hook can repair bgIsolation itself.

bcherny collaborator · 2 months ago

Thanks for the detailed report and repro script — this was a real bypass on the version you tested (2.1.207), and it has since been fixed.

I re-ran your scenario on 2.1.233 (Linux): repo at /tmp/repo, symlink /tmp/alias -> /tmp/repo, background session dispatched with cwd /tmp/repo, asked to write both /tmp/repo/canon.txt and /tmp/alias/alias.txt without entering a worktree. Both writes were blocked identically with the "isolate into a worktree first" message, and neither file was created — the symlink-alias spelling no longer bypasses the isolation guard. Path containment is now resolved to canonical filesystem identity, and path spellings that can't be safely resolved are refused outright.

The fix shipped in 2.1.217 — see the changelog: "Fixed background session isolation not canonicalizing symlinked working directories, which could let sessions escape their workspace folder."

Closing as fixed — please update to 2.1.217 or later, and reply here if you can still reproduce it on a current version and we'll reopen.

🤖 Generated with Claude Code

github-actions[bot] · 9 days ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.