[BUG] WSL2: a read-deny path symlinked into /mnt/c fails bwrap for every Bash command, and is unremovable when it comes from managed settings
Summary
On WSL2, every sandboxed Bash command fails during bwrap setup when a read-deny path is a symlink pointing into the Windows mount (/mnt/c).
This is the same failure as #45122, which was closed as stale on 2026-05-27 and then locked. It still reproduces on 2.1.268, so I am filing a fresh report rather than commenting on a locked thread.
The part that is new since #45122: when the deny rule arrives through enterprise managed settings, the user cannot remove it. Read and Edit deny rules are merged into the sandbox configuration, and a deny entry added by one scope cannot be removed by another. The Bash tool is then unusable on that machine and the affected user has no setting they can change to recover.
Environment
- Claude Code 2.1.268, native sandbox (bwrap)
- WSL2, Ubuntu 26.04 LTS, kernel 6.18.33.2-microsoft-standard-WSL2
~/.awsis a symlink to/mnt/c/Users/<user>/.aws, a common way to share credentials with the Windows host
Repro
- In WSL2, make one of the deny paths a symlink into the Windows mount:
ln -s /mnt/c/Users/<user>/.aws ~/.aws
- Enable the sandbox and deny reads on that path, for example in
settings.json:
{
"sandbox": {
"enabled": true,
"filesystem": { "denyRead": ["~/.ssh", "~/.aws", "~/.config/gcloud"] }
}
}
- Ask Claude to run any Bash command, for example
ls.
Every command fails before the command itself runs:
bwrap: Can't mount tmpfs on /newroot/home/<user>/.aws: No such file or directory
The path exists. It is a symlink whose target lives on the Windows mount.
What is and is not affected
- Deny paths that do not exist are skipped silently. Only the symlinked one fails. We confirmed this by creating
~/.sshand~/.config/gcloudas real empty directories: those passed, and the run still failed on the symlinked~/.aws. - The in-session diagnosis suggests
mkdir -p ~/.aws, which does not apply here. The directory is not missing; it is a symlink. - macOS (Seatbelt) is unaffected. It does not mask by mounting.
Why the user cannot work around it
Per the sandboxing documentation, Read and Edit deny rules are merged into the final sandbox configuration, and a deny entry can be added by any scope but removed by none.
On a machine where Read(~/.aws/**) comes from enterprise managed settings, we verified:
- removing
~/.awsfrom the user's ownsandbox.filesystem.denyReadandsandbox.credentials.filesdoes not help, and the/sandboxConfig tab still lists~/.awsamong the denied paths - the deny cannot be removed at the user scope at all
- the remaining options are replacing the symlink with a real directory, or changing the managed settings, neither of which is available to the user
Expected
Setting up the deny mask should not fail the whole sandbox when one deny path cannot be masked. Mask without following the symlink, or skip the entry with a warning, the way non-existent paths are already skipped.
Impact
On any WSL2 machine where a denied path is symlinked into /mnt/c, the Bash tool stops working entirely the moment the sandbox is enabled. Sharing ~/.aws or ~/.ssh with the Windows host this way is a normal WSL setup, so this is reachable without any unusual configuration. When the deny arrives from managed settings, the user cannot restore Bash themselves.
Related
- #45122, the same symptom with a symlinked
~/.aws, closed as stale and locked, still reproducing on 2.1.268 - #86855, the same class of failure (a deny path that cannot be masked brings down the whole sandbox) with a different cause (a read-only
/nix/store)
A smaller, separate observation from the same machine: on Linux the glob deny rule Read(./.env.*) is reported as ignored, with the warning Glob patterns not fully supported on Linux. The same settings therefore take effect differently on macOS and Linux. I am not filing that here.