Run OpenCode inside a bubblewrap sandbox for security isolation.
opencodebox is a bash script that runs OpenCode (AI coding assistant) inside a sandbox using bubblewrap. The sandbox provides process isolation with Linux namespaces (PID, IPC, UTS) and restricted filesystem access.
- Process Isolation: Uses unshare PID, IPC, and UTS namespaces
- Controlled Filesystem: Most system filesystem mounted read-only
- Custom Bind Mounts: Add read-write or read-only access with
--withand--with-ro - Mise Support: Integrated with mise for tool management
- SSH Agent Forwarding: Supports SSH commit signing through the host
ssh-agent - Seccomp Sandbox Filter: Mitigates kernel privilege escalation vulnerabilities (see details)
- bubblewrap (
bwrap) - for sandboxing - opencode - AI coding assistant
Security Note (CVE-2017-5226): Bubblewrap sandbox can be escaped via
TIOCSTIioctl if the kernel allows it. Since Linux 6.2,TIOCSTIis restricted whendev.tty.legacy_tiocsti=0(default). On older kernels, ensure bubblewrap >= 0.1.5 (usessetsid()fix) or enable seccomp filtering. Theinstall.shscript performs this check automatically.
curl -fsSL https://raw.githubusercontent.com/fityannugroho/opencodebox/main/install.sh | bashThis installs opencodebox to ~/.local/bin/opencodebox. Make sure ~/.local/bin is in your PATH.
Verify the installation :
opencodebox --versionopencodebox is a wrapper for the opencode command. All arguments are passed through to opencode inside the sandbox.
opencodebox [OPTIONS] [OPENCODE_ARGS...]Note: The
opencodecommand stays available when you need it. We didn't replace it.
opencodebox adds the following options :
--with /host[:/sandbox]- Bind host path read-write to sandbox--with-ro /host[:/sandbox]- Bind host path read-only to sandbox
These options allow you to specify additional directories to mount inside the sandbox for read-write or read-only access.
# Run sandboxed opencode in current directory
opencodebox
# Run sandboxed opencode with read-write access to /data
opencodebox --with /data
# Run sandboxed opencode with read-write access to /mnt/data mapped to /workspace/data
opencodebox --with /mnt/data:/workspace/data
# Run sandboxed opencode with read-only access to config
opencodebox --with-ro /etc/hosts
# Run sandboxed opencode server with specified bind mounts
opencodebox --with /data --with-ro /config serve- Parse arguments (
--with,--with-ro,--version,--help) - Check prerequisites (bwrap and opencode)
- Load seccomp sandbox filter (see details)
- Enforce security restrictions:
- Rejects running from
$HOME,~/.ssh,~/.gnupg, or their ancestors - Rejects sensitive paths in
--with/--with-robinds - Validates
~/.sshdirectory permissions (must be0700)
- Rejects running from
- Build bubblewrap sandbox with namespace isolation and bind mounts
- Setup SSH (sanitized
.pubkeys,known_hosts, agent forwarding) - Add conditional tool mounts (bun, npm, pnpm, uv, pipenv, cargo, git, mise) and extra bind mounts
- Execute opencode inside the sandbox
Read-Only:
/usr- System basics/etc/ssl- SSL/TLS certificates/etc/ca-certificates- CA certificate store/etc/alternatives- System alternatives (managed by update-alternatives)$HOME/.local- User local data (except keyrings/tool data)$HOME/.cache/opencode- OpenCode cache$HOME/.ssh/*.pub- Sanitized OpenSSH public key material, when$HOME/.sshis not a symlink$HOME/.ssh/known_hosts- SSH host key, read-only, for Git-over-SSH host verificationgpg.ssh.allowedSignersFile- Configured SSH allowed signers file (if configured)- OpenCode:
.config/opencode,.agents
Read-Write:
- Current project directory (
$PWD) $HOME/.local/share/opencode- OpenCode application data
Tmpfs (Private, writable per-session):
/tmp- Temporary files$HOME/.cache- Universal cache$HOME/.local/share/keyrings- Exclude private keyring (if exists on host)
Each tool is mounted only when command -v <tool> succeeds on the host. If the tool is not installed, none of its directories are bound into the sandbox.
| Tool | Read-Only Bind | Tmpfs |
|---|---|---|
| Bun | ~/.bun |
~/.bun/install/cache |
| npm | ~/.npmrc |
~/.npm |
| pnpm | ~/.config/pnpm |
~/.local/share/pnpm/store |
| uv | ~/.config/uv |
— |
| pipenv | — | ~/.local/share/virtualenvs |
| Rust/Cargo | ~/.rustup, ~/.cargo/bin, ~/.cargo/config.toml |
~/.cargo/registry |
| Git | ~/.gitconfig |
— |
| Mise | ~/.config/mise, ~/.local/share/mise, ~/.cache/mise |
— |
opencodebox enforces several security restrictions to prevent sandbox escape:
- Project directory: Cannot run from
$HOME,~/.ssh,~/.gnupg, or their ancestors. Use a dedicated project directory. - Bind mounts:
--withand--with-roreject paths that point to or enclose sensitive locations ($HOME,~/.ssh,~/.gnupg). - SSH directory:
~/.sshmust have permissions0700. Fix with:chmod 700 ~/.ssh
If SSH_AUTH_SOCK points to a valid socket, opencodebox forwards that socket into the sandbox. This allows SSH commit signing with keys already loaded by ssh-add on the host. This feature does not mount private SSH keys into the sandbox.
For Git SSH signing, use a public key path such as ~/.ssh/id_ed25519.pub, or an inline key::ssh-ed25519 ... value. Validates and sanitizes .pub files (rejects symlinks, hardlinks, multi-line files; validates key type, base64 format, and OpenSSH key structure with ssh-keygen). The sandbox receives sanitized key material only (<key-type> <key-data>), so comments or extra file content are not exposed.
For Git-over-SSH network operations, known_hosts is mounted read-only when available. This allows host verification without exposing private keys. ~/.ssh/config is not mounted by default because it can contain broader host-specific behavior; bind it explicitly with --with-ro ~/.ssh/config only when needed.
For local SSH signature verification, the configured gpg.ssh.allowedSignersFile is mounted read-only when it is an absolute regular file.
Note:
.pubvalidation occurs at script startup. There is a small TOCTOU window between reading and validating each.pubfile; this is an accepted limitation of shell scripting.
Git-over-SSH network operations may still need explicit read-only binds for files such as ~/.ssh/config in custom setups. User-provided binds and the current project bind can expose private keys if they include those files, so avoid binding ~/.ssh wholesale.
Forwarding an agent still lets sandboxed processes ask the agent to authenticate or sign while the socket is available. Use a dedicated signing key and consider ssh-add -c -t 1h ~/.ssh/signing_key for confirmation and expiry.
opencodebox includes a seccomp BPF filter that blocks socket creation for several protocol families to mitigate kernel privilege escalation vulnerabilities from inside the sandbox:
| Vulnerability | CVEs | Blocked Sockets |
|---|---|---|
| Copy Fail | CVE-2026-31431 | socket(AF_ALG, *, *) |
| Dirty Frag (ESP) | CVE-2026-43284 | socket(AF_INET/AF_INET6, *, IPPROTO_ESP) |
| Dirty Frag (ESP Bypass) | CVE-2026-43284 | socket(AF_NETLINK, *, NETLINK_XFRM), setsockopt(*, IPPROTO_UDP, UDP_ENCAP, *) |
| Dirty Frag (RxRPC) | CVE-2026-43500 | socket(AF_RXRPC, *, *) |
| Dirty Frag (IPCOMP) | CVE-2026-43284 | socket(AF_INET/AF_INET6, *, IPPROTO_IPCOMP) |
These are defense-in-depth mitigations and do not replace kernel patches. Supported architectures: x86_64 and aarch64.
The filter is automatically applied if the corresponding .bpf file is available; otherwise a warning is displayed and the sandbox runs without it. The seccomp filter is stored at ~/.local/share/opencodebox/seccomp-security.bpf after installation.
- Copy Fail — CVE-2026-31431
- Dirty Frag — CVE-2026-43284 / CVE-2026-43500
- Ubuntu Security Advisory — Dirty Frag
- AWS Security Bulletin — 2026-027
To generate the seccomp BPF filter files (.bpf):
Dependencies:
- gcc - C compiler
- libseccomp-dev - libseccomp development headers and library
Install on Ubuntu/Debian:
sudo apt install gcc libseccomp-devCompile and generate:
# Compile the BPF generator
gcc -o seccomp/seccomp-security-gen seccomp/seccomp-security-gen.c -lseccomp
# Generate BPF filters for each architecture
./seccomp/seccomp-security-gen x86_64 > seccomp/seccomp-security-x86_64.bpf
./seccomp/seccomp-security-gen aarch64 > seccomp/seccomp-security-aarch64.bpf
# Clean up compiled generator
rm seccomp/seccomp-security-genThe .bpf filter files are pre-generated and shipped with the repository, so end users do not need these development dependencies.