anthropics / anthropics/claude-code

Write tool does not enforce the working-directory sandbox that Bash enforces

Ouverte
#88,038 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
area:permissions area:sandbox area:security bug has repro platform:macos stale
Langage dominant
Python
Étoiles
145k
Forks
23.1k
Métriques de merge des PR
Métriques de PR en attente

Description

## Summary

When Claude Code is invoked with a working directory restriction (e.g. `claude -p` from a `cd && exec claude ...` subshell, with a `--settings` file granting `Write`), the `Bash` tool correctly refuses to write outside that directory, but the `Write` tool does not — it writes to arbitrary paths on the filesystem regardless of the working-directory boundary that `Bash` enforces.

## Environment

- `claude` CLI (non-interactive `-p` mode)
- macOS (Darwin arm64)
- Reproduced with `--model claude-haiku-4-5`, `--permission-mode acceptEdits`, and a `settings.json` allow-listing `Read, Grep, Glob, Edit, Write` and `Bash(git:*)` among others (no explicit deny/allow for arbitrary paths)

## Steps to reproduce

1. Create a git worktree as a subdirectory of a larger project, e.g. `/.worktrees/foo` inside ``.
2. Invoke `claude -p` with cwd set to the worktree via a subshell (`( cd /.worktrees/foo && exec claude -p "..." --settings settings.json --permission-mode acceptEdits )`), granting `Write` (and not granting `--add-dir` for anything outside the worktree).
3. Ask the model to write a file at an absolute path outside the worktree — e.g. two directories up, at `/MARKER.txt` — first via the `Bash` tool (`echo x > /MARKER.txt`), then via the `Write` tool targeting the same absolute path.

## Expected

Both tool calls are denied — the working-directory boundary should apply uniformly regardless of which tool is used to write the file.

## Actual

- `Bash` write to the out-of-bounds path: **denied** — "blocked by security restriction to working directory" (or similar wording reported by the model).
- `Write` tool call to the identical out-of-bounds path: **succeeds**. Verified independently on disk (outside the model's own self-report) — the file is created at the requested out-of-bounds path with the requested content.

Re-tested with every Claude-Code-related environment variable (`CLAUDECODE`, `CLAUDE_CODE_SESSION_ID`, `CLAUDE_PID`, `CLAUDE_CODE_CHILD_SESSION`, etc.) explicitly unset before invoking `claude -p`, in case session/parent-process linkage was involved — the `Write` tool still escaped the working directory identically. So this does not appear to depend on environment inheritance or nested/child-session state; it reproduces from a clean environment.

## Why this matters

This was found while debugging an internal automation pipeline that spawns `claude -p` per-task inside git worktrees, one per task, explicitly to keep each task's file writes isolated to its own worktree — the whole isolation model assumes `Bash`, `Write`, and `Edit` all respect the same working-directory boundary. In a real (non-synthetic) run, a task's `Write`/`Edit` calls landed files outside its intended worktree, in a sibling checkout of the same repository that a human had interactively checked out at the time, and a subsequent `git commit` (via `Bash`, correctly scoped to whatever directory it was actually invoked from) committed those files there instead of in the intended worktree — producing a duplicate, unintended commit on a branch the automation was never supposed to touch. No data was lost and nothing was pushed in our case, but the mechanism generalizes: any workflow that relies on `Write`/`Edit` respecting the same directory sandbox `Bash` enforces cannot currently assume that.

## Suggested fix

Enforce the same working-directory/`--add-dir` boundary check for `Write` and `Edit` (and any other file-mutating tool) that `Bash` already applies, rather than only gating `Bash`.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Piste de recherche

Start with the Bash, Write, and Edit tool permission paths and reproduce the absolute-path case from the issue using claude -p, a working directory, and --add-dir settings. Compare the working-directory boundary check applied to Bash with the checks used by Write and Edit; done means out-of-bounds mutations are denied while permitted in-bounds writes still succeed.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
cli, security
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
Active
Clarté
Clairement spécifiée
Accessibilité débutants
65/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.