Per-session private /tmp, covering background jobs

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 25, 2026

The problem

TMPDIR, CLAUDE_TMPDIR and CLAUDE_CODE_TMPDIR all point at /tmp/claude-<uid> - one directory shared by every session and every project on the host - and files land there 0644. Measured (2026-07-21) from one ordinary session: session directories belonging to another project, other tools' scratch files, and stray files left by earlier sessions, all readable. The standing guidance ("use $TMPDIR for temporary files") is what routes work into that shared tree.

Why no user-side fix reaches it

Two shapes tried, both fail:

  • sandbox.filesystem.denyRead is static and "only my own session" is not expressible: the session id is dynamic, and an allowRead carve-back for a path that does not exist when the sandbox starts does not get re-mounted.
  • A permission-hook rule keyed on the session id breaks measurably: one session's CLAUDE_CODE_SESSION_ID was 65394dc6… while the harness wrote its own background-task output under 676629c7… (a child session). "Only my id" denies the session its own output. A hook also matches command strings, not syscalls, so anything reading the file without naming it passes anyway.

The background-job half (stronger)

A session running as a background job is told, in its own system instruction, to use $CLAUDE_JOB_DIR/tmp precisely because parallel jobs collide in a shared /tmp - so the premise is already agreed with upstream. But that directory refuses writes:

$ touch "$CLAUDE_JOB_DIR/tmp/probe.sh"
touch: cannot touch '<job dir>/tmp/probe.sh': Read-only file system

It sits under the harness's own state, outside allowWrite and read-denied by policy. The instruction names the one directory the sandbox will not accept, and the fallback the session reaches for is $TMPDIR - the shared tree above. The guidance routes work into the exposure instead of out of it, costing turns to an error that names no cause.

(Widening allowWrite to reach the job directory would put harness state inside the writable set to fix a temp-file problem - the wrong trade in the other direction.)

Ask

A private /tmp per session, via mount namespace, covering background jobs as well as interactive sessions. That is the only place the isolation can be expressed. Failing that, the cheaper half on its own: the background-job instruction should stop promising a directory the sandbox refuses.

View original on GitHub ↗