Skip to content

[BUG] plugin eval: sandboxed Bash cannot write the run workspace when TMPDIR is under /tmp ("Read-only file system") #104797

Open

Description

@LeBwa1221

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code (tested on 2.1.309; 2.1.310 is out and not retested)

What's Wrong?

claude plugin eval creates each run's workspace under $TMPDIR (default /tmp), for example /tmp/claude-eval-XXXX/home/cwd. Bash in the sandbox then cannot write there. The eval cannot pass any case that writes a file with Bash.

What Should Happen?

Sandboxed Bash can write to the run's working directory, as the docs say ("Writes are confined to the run's workspace"), wherever TMPDIR points.

Error Messages/Logs

Exit code 1
/bin/bash: line 1: out.txt: Read-only file system

(trace cwd: /tmp/claude-eval-U7fnrz/home/cwd)

Steps to Reproduce

  1. Linux (here: Ubuntu 24.04 container; bubblewrap and socat installed; the sandbox works).
  2. One eval case: prompt.md with allowed_tools: [Bash], body Use the Bash tool to run: echo ok > out.txt, and a file_exists grader for out.txt.
  3. claude plugin eval . --trust-plugin --allow-tools Bash --runs 1 --ablation none with default TMPDIR: score 0, error above.
  4. TMPDIR=$HOME/tmp claude plugin eval ... (same command): score 1.

Is this a regression?

I don't know.

Claude Code Version

2.1.309 (Claude Code)

Claude Model

Other (claude-haiku-5-5 via --model)

Platform

Anthropic API

Operating System

Other Linux (Ubuntu 24.04 container on Docker Desktop, Windows 11 host)

Terminal/Shell

Non-interactive/CI environment

Additional Information

Not checked on a non-container Linux host. /tmp in the container is a tmpfs mount.

Activity

  1. 6t9xstar commented on Nov 5, 2026

    @6t9xstar

    This error occurs because of an inversion in Linux VFS mount namespace ordering between the sandbox's /tmp isolation and the project directory bind-mount.

    Root Cause

    Most sandboxes isolate /tmp to prevent inter-process host pollution by mounting a fresh tmpfs over /tmp:

    mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777");

    If your workspace is located at /tmp/eval-123/cwd:

    1. If the sandbox bind-mounts /tmp/eval-123/cwd before masking /tmp with tmpfs, the new tmpfs mount completely shadows and hides the workspace mount, turning writes into errors or sending them into an unmapped tmpfs.
    2. Conversely, if /tmp is remounted read-only (MS_RDONLY) as a security measure, any directory underneath /tmp inherits the read-only flag from the VFS super-block unless explicitly re-bound and remounted MS_BIND | MS_REC.

    The Fix

    To support projects located in /tmp, follow this mount sequence:

    1. Check for Root Equality:
      if project_root != Path::new("/tmp") {
          // Only mount private tmpfs over /tmp if the project itself isn't /tmp
          mount_private_tmpfs("/tmp", "mode=1777")?;
      }
    2. Bind-Mount the CoW Workspace Second:
      Always bind-mount the CoW overlay (or working directory) after the tmpfs for /tmp is configured. If the workspace is inside /tmp, recreate the directory structure inside the new tmpfs before bind-mounting:
      let _ = std::fs::create_dir_all(project_root);
      mount(merged_overlay, project_root, NULL, MS_BIND | MS_REC, NULL)?;
    3. Landlock Ruleset Ordering:
      In your Landlock ruleset, ensure both the project root descriptor and /tmp descriptor are given AccessFs::from_all(abi). When Landlock evaluates path access, having the project root descriptor registered ensures descendant files within the workspace receive explicit write access regardless of ancestor mounts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:sandboxbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:linuxIssue specifically occurs on Linux

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions