Filesystem Sandbox
Limit Agent filesystem visibility with Linux bubblewrap mount namespaces and workspace-scoped data isolation.
The filesystem sandbox places each Agent subprocess and its tools in a Linux bubblewrap (bwrap) mount namespace. It controls filesystem visibility and writability; it does not restrict network access, environment-variable values, or executable permissions.
MOPHEUS_SANDBOX_ENABLED=trueThe sandbox is enabled by default, including when this variable is unset or blank. Set it to false or off to disable it; other values also keep the sandbox enabled.
It is effective only on Linux hosts with a usable bwrap installation. The daemon runs a minimal capability probe (bwrap --ro-bind / / true) before wrapping tasks, because an installed binary can still be blocked from creating a user namespace by AppArmor, SELinux, seccomp, kernel settings, or a container runtime. If the probe fails, the daemon logs the original error and runs the task unsandboxed. Only a successful probe and command wrap mark the task as sandboxed.
To diagnose a Linux host, run:
bwrap --ro-bind / / true
sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null || true
sysctl kernel.unprivileged_userns_clone 2>/dev/null || true
sysctl user.max_user_namespaces 2>/dev/null || true
unshare -Ur trueUbuntu 23.10 and later commonly enforce the restriction through AppArmor. Docker, LXC, and CI environments may impose the same restriction at the host or container security-policy level. This is a Linux capability issue, not an Ubuntu-only feature; check the active kernel and security policy for other distributions.
Ubuntu Troubleshooting
The Ubuntu APT package is named bubblewrap; bwrap is the installed command. Install it and verify it as the regular user that runs the Mopheus daemon:
sudo apt update
sudo apt install bubblewrap
bwrap --version
bwrap --ro-bind / / trueDo not rely on a test run only as root: root may succeed even when the daemon user cannot create a user namespace. If APT cannot locate bubblewrap, check that the package sources for the installed Ubuntu release are enabled, then run sudo apt update again.
On Ubuntu 23.10 and later, if the probe fails, check the AppArmor restriction and the kernel limits:
sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null || true
sysctl kernel.unprivileged_userns_clone 2>/dev/null || true
sysctl user.max_user_namespaces 2>/dev/null || true
sudo aa-status | grep -i bwrap || true
sudo journalctl -k | grep -i apparmor | tail -50If the kernel logs show an AppArmor denial, there are two host-level options:
-
Disable the restriction globally for a temporary diagnosis.
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 bwrap --ro-bind / / trueTo persist this setting, add
kernel.apparmor_restrict_unprivileged_userns=0to a file under/etc/sysctl.d/and runsudo sysctl --system. This allows unconfined applications to create user namespaces, so it should be limited to machines where that broader security tradeoff is acceptable. -
Allow user namespaces for bwrap while keeping the global restriction enabled.
First check whether a profile is already attached to bwrap. Do not add a second profile for the same executable; inspect and adjust the existing profile instead. The package may also provide a tested profile under
/usr/share/apparmor/extra-profiles/:command -v bwrap sudo aa-status | grep -i bwrap || true find /etc/apparmor.d /usr/share/apparmor/extra-profiles -iname '*bwrap*' -o -iname '*bubblewrap*' 2>/dev/null grep -R "userns" /etc/apparmor.d 2>/dev/nullIf there is no existing profile and
command -v bwrapreturns/usr/bin/bwrap, create/etc/apparmor.d/usr.bin.bwrapwith this Ubuntu profile:sudo vi /etc/apparmor.d/usr.bin.bwrap abi <abi/4.0>, include <tunables/global> /usr/bin/bwrap flags=(unconfined) { userns, } sudo apparmor_parser -r /etc/apparmor.d/usr.bin.bwrap sudo aa-status | grep -i bwrap bwrap --ro-bind / / trueReplace
/usr/bin/bwrapand the profile filename ifcommand -v bwrapreports another path. Theuserns,rule grants namespace creation to processes attached to this bwrap profile;flags=(unconfined)means AppArmor does not otherwise confine that executable. Review whether this host-wide bwrap exception is appropriate, and test the actual Mopheus providers. To roll back this manually created profile, unload it and remove the file:sudo apparmor_parser -R /etc/apparmor.d/usr.bin.bwrap sudo rm /etc/apparmor.d/usr.bin.bwrap
The second option is preferred for a shared host because it preserves the restriction for unrelated executables. If the probe still fails after AppArmor allows userns, check that kernel.unprivileged_userns_clone is enabled and user.max_user_namespaces is greater than zero. Mopheus logs the probe output and runs the task unsandboxed when the capability remains unavailable.
Workspace Isolation Boundary
The sandbox isolates by workspace, not by individual task. Tasks in one workspace can collaborate and share required runtime data; data from other workspaces is hidden.
| Path or scope | Access | Details |
|---|---|---|
/ | Read-only | System commands, libraries, and configuration remain readable and executable. |
| Current task work directory | Read-write | Code, generated files, and task logs. |
| Other task directories in the current workspace | Read-write | The collaboration scope for tasks in the same workspace. |
Current workspace .repos/<workspaceId> bare cache | Read-write | Required by worktree .git pointers and normal Git operations. |
/tmp | Read-write | Maps to /tmp/mopheus-<workspaceId> on the host and is shared by this workspace. |
| Other workspaces' task directories and bare caches | Hidden | A tmpfs overlay prevents both reads and writes. |
Other host /tmp content | Hidden | Only the current workspace temporary directory is remounted. |
$HOME | Read-write | Provider configuration, sessions, and symlinks continue to work. |
Paths in MOPHEUS_SANDBOX_DENY | Hidden | Covered by an empty tmpfs. |
The sandbox therefore isolates task data across workspaces, but does not isolate tasks within the same workspace or fully isolate $HOME by default.
Sensitive Paths
~/.ssh remains visible by default so SSH Git operations keep working. Hide extra credentials for untrusted agents with comma-separated absolute paths:
MOPHEUS_SANDBOX_DENY=~/.ssh,~/.aws,~/.gnupgAny operation requiring a hidden credential will fail. Evaluate the minimum credential set together with the task's Git and cloud-access requirements.
Personal Configuration Files
When sandboxing is active, enabled personal configuration files are staged under <WorkDir>/.config/<workspaceId>/<taskId>/. The daemon preserves each file's path relative to $HOME and overlays individual files into the sandbox; the staging directory itself is never mounted.
- File modes determine read-only or read-write mounting.
- Staging is removed after success, failure, cancellation, timeout, or startup failure.
- If sandboxing is unavailable, the task continues without configuration delivery.
- Startup cleanup removes only UUID-shaped Mopheus staging roots under
.config.
Managed SSH keys and SSH configuration fragments are delivered through this path. Private key bytes are encrypted at rest and are never exposed to browsers; existing host SSH configuration remains unchanged.
Providers and Limits
Supported CLI providers use this outer sandbox on Linux. Codex disables its inner sandbox when this layer is active to avoid nesting. Unsupported providers warn and degrade to unsandboxed execution. See Provider CLI for the capability matrix.
This is a process-level mount sandbox. It can be combined with containers, but does not replace network controls, credential management, access control, or container isolation.
| Variable | Default | Description |
|---|---|---|
MOPHEUS_SANDBOX_ENABLED | true | Enable a bwrap mount namespace for Agent subprocesses. Enabled when unset or blank; only false or off disables it. |
MOPHEUS_SANDBOX_DENY | — | Additional absolute paths to hide, comma-separated. |