Skip to content

security: make denyRead directories read-only in Linux sandbox#150

Open
patrick-premont wants to merge 1 commit intoanthropic-experimental:mainfrom
patrick-premont:patrick/fix-tmpfs-writable
Open

security: make denyRead directories read-only in Linux sandbox#150
patrick-premont wants to merge 1 commit intoanthropic-experimental:mainfrom
patrick-premont:patrick/fix-tmpfs-writable

Conversation

@patrick-premont
Copy link
Copy Markdown
Contributor

Fixes #149.

Problem

denyRead directories on Linux are mounted using --tmpfs, which hides the original contents but creates a writable mount. A sandboxed process can write to directories that should be inaccessible.

The writes go to in-memory tmpfs (not the real filesystem), so the original data is safe and writes are lost on sandbox exit. But the process observes writes succeeding where they should fail, violating the expected security contract.

The file-level deny path (--ro-bind /dev/null) is not affected — only directory-level deny uses --tmpfs.

Fix

Replace --tmpfs with --ro-bind using an empty temporary directory for directory read deny. This hides directory contents (same as before) while keeping the mount read-only.

The fix follows the existing pattern used for non-existent deny paths (#126), which already creates temp directories as --ro-bind sources and tracks them via bwrapMountPoints for cleanup.

Safety

A single empty temp directory is created via mkdtempSync (unique, 0700) and reused as the --ro-bind source for all directory read-deny mounts. It is tracked in bwrapMountPoints for cleanup by cleanupBwrapMountPoints() after each command and on process exit. This reuses the cleanup infrastructure from #126.

Edge case — denyRead + allowWrite overlap: If the same path appears in both denyRead and allowWrite, the read-only --ro-bind overlay now takes precedence, making the path read-only. Under the old --tmpfs behavior, writes went to ephemeral tmpfs (not the real path), so allowWrite was effectively a no-op for denyRead paths either way. This overlap is not a practical configuration.

Testing

Three new integration tests added:

  • should block reads from denyRead directory — verifies content hiding still works
  • should block writes to denyRead directory when no writes allowed — verifies the fix with allowWrite: []
  • should block writes to denyRead directory within writable parent — verifies the fix when denyRead path is inside an allowWrite path

Tested with bubblewrap 0.9.0 on Ubuntu 24.04 (Docker with --privileged).

Replace --tmpfs with --ro-bind of an empty directory for denyRead
directory paths. --tmpfs hides contents but creates a writable mount,
allowing sandboxed processes to write to denied paths. --ro-bind
ensures the mount is read-only.

Follows the existing pattern from anthropic-experimental#126 for non-existent deny paths.
Temp directories are tracked via bwrapMountPoints for cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

denyRead directories are writable via --tmpfs mount in Linux sandbox

1 participant