anthropics / anthropics/claude-code
Sandboxed Bash wedges permanently when the working directory is on a read-only filesystem (no cwd recovery)
- Lenguaje dominante
- Python
- Estrellas
- 145k
- Forks
- 23.1k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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?
When the sandboxed Bash tool's working directory ends up on a read-only filesystem (e.g. a read-only bind mount the agent `cd`s into), **every subsequent Bash command fails during sandbox setup, before the command runs**, and the session cannot recover on its own.
Because setup fails before the command executes, even a `cd` back to a writable directory never runs — the shell is sealed out of its own recovery. Read/Edit/Glob/Grep still work (they don't spawn a sandboxed shell), so only the Bash tool dies. A single `cd` into a read-only mount kills Bash for the rest of the session.
**Root cause.** For every Bash command, sandbox setup prepares two things **under the shell's current working directory**, before bwrap launches:
1. a `.claude/settings.json` write-mask (a bind rule) — bwrap must *create* the mount-point file for it, which fails on a read-only fs;
2. an atomic-write staging dir `/.claude/.cc-writes`, created with a plain `mkdir`, which also fails on a read-only fs.
Both run on **every** invocation (a bare `pwd` triggers them), keyed on the cwd persisted from the *previous* command — so once the cwd is a read-only mount, the next command's setup targets `/.claude/…` and aborts. The intent ("prepare to write next to the working directory") is meaningless on a filesystem nothing can write to, but setup treats the failure as fatal.
### What Should Happen?
A read-only working directory should make the per-command scratch/mask setup a no-op (nothing can be written there anyway) and Bash commands should keep working — or the session should recover the cwd to a writable path, exactly as it already does when the working directory has been *deleted* (it logs `Shell CWD "…" no longer exists, recovering to "…"` and resets the tracked cwd).
### Error Messages/Logs
```shell
bwrap: Can't create file at /.claude/settings.json: Read-only file system
bwrap: Can't mkdir /.claude: Read-only file system
```
### Steps to Reproduce
Minimal, no specific project or model. Any Linux host with the CLI:
1. Create a read-only directory the agent can `cd` into:
```
mkdir -p /tmp/ro && echo hello > /tmp/ro/file.txt
sudo mount --bind /tmp/ro /tmp/ro
sudo mount -o remount,ro,bind /tmp/ro
# (or in a container, mount a volume read-only: -v /tmp/ro:/work/ro:ro)
```
2. In a session with the Bash sandbox enabled, run each as a separate Bash tool call:
```
cd /tmp/ro && pwd # OK -> /tmp/ro
ls # OK (first command after the cd)
pwd # FAILS -> bwrap: Can't mkdir /tmp/ro/.claude: Read-only file system
cd /tmp && pwd # FAILS identically -- the escape never runs
```
From the 3rd command on, every command (including `echo`, `true`, or the `cd` that would fix it) fails at sandbox setup.
**Isolating the mechanism (no CLI needed)** — the two failing setup operations, reproduced directly with bubblewrap:
```
bwrap --dev-bind / / --ro-bind /tmp/ro /tmp/ro -- sh -c 'cd /tmp/ro && pwd'
# -> /tmp/ro (exit 0; denying the mount as a whole is fine)
bwrap --dev-bind / / --ro-bind /dev/null /tmp/ro/.claude/settings.json -- true
# -> bwrap: Can't create file at /tmp/ro/.claude/settings.json: Read-only file system (exit 1)
```
### Claude Model
_No response_
### Is this a regression?
No, this never worked
### Last Working Version
_No response_
### Claude Code Version
Reproduced on 2.1.226 and 2.1.229; present on 2.1.235. bubblewrap 0.11.0. Independent of model and API platform.
### Platform
Other
### Operating System
Other Linux
### Terminal/Shell
Non-interactive/CI environment
### Additional Information
**The asymmetry that points at a small fix:** the tool already recovers when the working directory has been *deleted* (ENOENT → resets the tracked cwd to a writable fallback, `Shell CWD "…" no longer exists, recovering to "…"`), but not when the cwd is *read-only* (EROFS on the staging setup). Either fix is sufficient:
1. **Tolerate `EROFS`/`EACCES`** when pre-creating the per-command staging dir (`.claude/.cc-writes`) and the settings write-mask under the cwd — a read-only fs cannot host a planted settings file or a staging dir, so skipping them there is safe.
2. **Extend the existing deleted-cwd recovery** to also reset the cwd when it is read-only.
**Related** (same "sandbox setup must write under a read-only path" class, other angles): #50781 (`Can't create file at .zshrc` kills all Bash), #46560 (cwd is `~/.claude`), #25603 (denyWithinAllow artifacts in the working dir), #43096 (`/tmp/claude` TMPDIR chicken-and-egg). This report is the **general case**: any read-only mount reached by a normal `cd`, with the deleted-cwd-recovers / read-only-cwd-wedges asymmetry.
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Línea de trabajo
Reproduce the failure on Linux with the Bash sandbox and bubblewrap commands from the report, using a read-only mounted working directory. Trace the per-command sandbox setup for the settings write-mask and .claude/.cc-writes staging directory, then compare it with the existing deleted-cwd recovery; done means Bash commands continue working or the cwd recovers after entering a read-only mount.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- bash, linux, python
- Área
- cli, operating-systems, security
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Activo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 55/100