Bash sandbox filesystem isolation does not confine on Linux-in-Docker — default allow-list AND deny-list both bypassed (atomic repro; corroborates #32226, #29048)
Corroboration for #32226 / #29048: Bash-sandbox filesystem isolation does not confine on Linux-in-Docker (default allow-list AND deny-list), with an atomic namespace-verified reproduction
Not a new report. This corroborates and extends:
- #32226 "sandbox denyRead seems ineffective" (closed not planned)
- #29048 in-process Write/Edit bypass bwrap; permission-rule-only gating
Versions: 2.1.224 and 2.1.227 (native binary). Host macOS/OrbStack 29.4.0;
container Ubuntu 26.04, bubblewrap + socat present.
What's new vs the existing issues
The existing reports show deny-list carve-outs being ineffective. This adds
that the default allow-list confinement also does not hold: a Bash
subprocess writes outside cwd and the session temp dir and the file lands on
the real filesystem — while the command is provably running inside the sandbox.
Atomic, outside-verified reproduction
One sandboxed command reports its own mount namespace and writes outside cwd:
NS=mnt:[…621] WROTE=True # the sandboxed command
container mnt: mnt:[…626] # differs → the command IS sandbox-wrapped
/home/dev/ATOMIC.txt on disk # a write outside cwd+temp landed for real
- Distinct mount namespace ⇒ the command is genuinely sandboxed (also
failIfUnavailable: true, so no silent unsandboxed fallback).
- Real on-disk existence, checked from a separate
docker exec⇒ not a
shadow/masked write.
Both simultaneously ⇒ the sandbox runs but does not confine filesystem access.
Deny-list arm (matches #32226): a denyWrite-listed pre-existing file, hashed
before/after a sandboxed append — hash changes, marker present in the real file.
Scope of reproduction
2.1.224 and 2.1.227; literal / glob / ${containerWorkspaceFolder} shapes;
managed, user, and ~/.srt-settings.json scopes; privileged and unprivileged
(seccomp userns) containers; managed floor present or hidden.
Secondary findings (unprivileged-container setup friction)
enableWeakerNestedSandbox: trueappears inert on 2.1.224/2.1.227: set in
all three scopes, bwrap still attempts a fresh /proc and fails
("Can't mount proc on /newroot/proc"). Workaround that works:
--security-opt systempaths=unconfined.
- Sandbox fails until a bind target exists at
/home/.mcp.json
("bwrap: Can't create file at /home/.mcp.json") — /home is root-owned;
pre-creating the file unblocks it.
Ask
- Reopen or cross-link #32226 with this default-allow-list evidence.
- A schema-valid-but-inert
sandbox.filesystemconfig should WARN at startup,
not pass silently — this is what made the gap invisible for so long.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗