CLAUDE_CODE_TMPDIR not respected for CWD tracking files on multi-user servers
Description
On shared multi-user Linux servers, Claude Code's CWD tracking files (/tmp/claude-<hex>-cwd) accumulate in /tmp/ and collide across users, causing "Permission denied" errors in stderr. The CLAUDE_CODE_TMPDIR environment variable does not fix this — it is only partially respected.
Steps to reproduce
- Set up a shared Linux server with multiple users running Claude Code
- Set
CLAUDE_CODE_TMPDIR=/var/tmp/claude(or any custom path) - Have multiple users run Claude Code sessions over time
- Observe
/tmp/claude-*-cwdfiles accumulating, owned by different users - Eventually a session gets a hex ID that collides with an existing file owned by another user →
EACCES
Expected behaviour
CLAUDE_CODE_TMPDIR should control where CWD tracking files are written, and they should be scoped per user (e.g. by UID) to prevent cross-user collisions.
Actual behaviour
CWD tracking files ignore CLAUDE_CODE_TMPDIR and always write to /tmp/claude-<hex>-cwd with no user scoping.
In the minified source (v2.1.68), the CWD file path depends on whether sandbox mode is enabled:
- Sandbox path (
useSandbox=true):join(sandboxTmpDir, "cwd-<id>")—sandboxTmpDiris built fromCLAUDE_CODE_TMPDIRand includes aclaude-<uid>subdirectory. This works correctly. - Non-sandbox path (default):
join(os.tmpdir(), "claude-<id>-cwd")— uses bareos.tmpdir()(/tmp), ignoringCLAUDE_CODE_TMPDIRentirely, with no user scoping.
The hex ID is only 4 digits (Math.floor(Math.random()*65536).toString(16).padStart(4,"0")), giving 65,536 possible values. On our server with 9 users, we have 2,392 accumulated files and collisions are routine.
Other temp paths (e.g. the Fm() helper function) correctly respect CLAUDE_CODE_TMPDIR and include user scoping via claude-<uid> subdirectories.
Suggested fix
The non-sandbox CWD file path should use CLAUDE_CODE_TMPDIR and include user scoping, consistent with how other temp paths are handled:
// Current (broken for non-sandbox)
cwdFilePath = join(tmpdir(), `claude-${id}-cwd`)
// Suggested fix
cwdFilePath = join(process.env.CLAUDE_CODE_TMPDIR || tmpdir(), `claude-${process.getuid()}-claude-${id}-cwd`)
Or reuse the existing Fm() helper that already handles this correctly.
Environment
- Claude Code version: 2.1.68
- OS: Debian Linux 6.1.0-40-amd64 (shared server, 9 users)
CLAUDE_CODE_TMPDIR=/var/tmp/claude(set but not respected for CWD files)
Additional context
Full analysis with source code references: https://gist.github.com/ShonaDouglasKT/e00d60776bd69a91b4a97ca62fe06545
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗