A sandboxed development environment for running Claude Code and OpenAI Codex with dangerous permissions safely enabled. Use strong agent defaults inside an isolated container instead of on your host.
This project lives at github.com/ComposableSecurity/ai-sandbox-devcontainer. It started from Trail of Bits’ claude-code-devcontainer and extends it for a broader "AI coding agent" sandbox.
# 1. Install devcontainer CLI (requires Node.js)
npm install -g @devcontainers/cli
# 2. Clone and install devc helper
git clone https://github.com/ComposableSecurity/ai-sandbox-devcontainer ~/.ai-sandbox-devcontainer
~/.ai-sandbox-devcontainer/install.sh self-install
# 3. Build the shared base image (one-time)
devc build-image
# 4. Start using it in any project
cd your-project
devc . # Install template + start container
devc shell # Open shell in container
# Alternative: Open in VS Code / Cursor
# Open the project folder, then Cmd+Shift+P → "Reopen in Container"That's it. Run claude or codex inside the container with full permissions enabled safely.
- OpenAI Codex — Codex-oriented VS Code / Cursor extension (
openai.chatgpt), persistent~/.codexdata via a Docker volume, and host read-only~/.codex/commands. Usedevc upgrade-agentsto refresh Claude Code and the Codex CLI (npm install -g @openai/codex@latest) inside a running container. - Shared Docker image — Workspaces reference a fixed image name (
my-ai-sandbox/devcontainer:localindevcontainer.json). Youdevc build-imageonce (from this repo); every new folder that runsdevc ./devc upreuses that image and only creates a new container plus per-workspace named volumes. You avoid rebuilding a full image for each project. - Custom Dockerfile mode — Use
devc . --customto copy a customizableDockerfileinto your project's.devcontainer/directory. This lets you add project-specific dependencies or modifications while still extending the base image. - Other tweaks — Naming, volume prefixes (
ai-sandbox-*), containerrunArgs(e.g. predictable--name), npm defaults incontainerEnv, and small quality-of-life changes on top of the upstream design.
Running agents with broad permissions on your host is risky: they can run commands without your usual guardrails. This devcontainer gives filesystem isolation so you get aggressive agent defaults without exposing your home directory or unrelated projects.
Designed for:
- Security audits — Review client code without risking your host
- Untrusted repositories — Explore unknown codebases safely
- Experimental work — Let agents change code freely inside the sandbox
- Multi-repo engagements — Shared workspace layout or per-project containers
-
Docker (one of):
- Docker Desktop — keep it running
- OrbStack
- Colima:
brew install colima docker && colima start
-
For terminal workflows (one-time):
npm install -g @devcontainers/cli git clone https://github.com/ComposableSecurity/ai-sandbox-devcontainer ~/.ai-sandbox-devcontainer ~/.ai-sandbox-devcontainer/install.sh self-install
That installs the devc helper into ~/.local/bin (see devc self-install).
Optimizing Colima for Apple Silicon
Colima’s defaults (QEMU + sshfs) are conservative. For better performance:
# Stop and delete current VM (removes containers/images)
colima stop && colima delete
# Start with optimized settings
colima start \
--cpu 4 \
--memory 8 \
--disk 100 \
--vm-type vz \
--vz-rosetta \
--mount-type virtiofsAdjust --cpu and --memory for your machine (e.g. 6/16 on Pro, 8/32 on Max).
| Option | Benefit |
|---|---|
--vm-type vz |
Apple Virtualization.framework (faster than QEMU) |
--mount-type virtiofs |
Much faster file I/O than sshfs |
--vz-rosetta |
Run x86 containers via Rosetta |
colima status should show Virtualization.framework and virtiofs.
Before (or after) cloning individual projects, build the image from this repo so all sandboxes share it:
devc build-imageThat produces my-ai-sandbox/devcontainer:local, which devcontainer.json in each copied template references. New workspaces only need the .devcontainer template + devc up (or devc .); they do not each trigger a full image rebuild unless you change the Dockerfile and run devc build-image again.
Each project gets its own container and per-instance volumes (history, Claude, Codex, gh). Good when you want isolation between repos.
Terminal:
git clone <repo>
cd repo
devc . # Drop in .devcontainer template + start container
devc shellVS Code / Cursor
-
Install Dev Containers
- VS Code:
ms-vscode-remote.remote-containers - Cursor:
anysphere.remote-containers
- VS Code:
-
Add the template:
devc . -
Open your project folder in VS Code, then:
- Press
Cmd+Shift+P(Mac) orCtrl+Shift+P(Windows/Linux) - Type "Reopen in Container" and select Dev Containers: Reopen in Container
- Press
One parent directory holds .devcontainer; you clone multiple repos under it. Volumes are shared for that devcontainer instance—good for one engagement with many related repos.
mkdir -p ~/sandbox/client-name
cd ~/sandbox/client-name
devc .
devc shell
# Inside the container:
git clone <client-repo-1>
git clone <client-repo-2>
cd client-repo-1
claude-yolo # or: codex-yoloFor headless servers or to skip the interactive login wizard:
claude setup-token # run on host, one-time
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
devc rebuild # rebuilds with tokenThe token is forwarded into the container. On each container creation, post_install.py runs a one-shot auth handshake so claude starts without the login wizard.
This works around Claude Code's interactive onboarding wizard always showing in containers, even with valid credentials (#8938).
If you don't set a token, the interactive login flow works as before.
devc . Install template + start container in current directory
devc . --custom Install template with custom Dockerfile build mode
devc build-image Build my-ai-sandbox/devcontainer:local (once; shared by workspaces)
devc up Start the devcontainer
devc rebuild Rebuild container (preserves persistent volumes)
devc destroy [-f] Remove container, volumes, and image for current project
devc down Stop the container
devc shell Open zsh shell in container
devc exec CMD Execute command inside the container
devc upgrade Upgrade Claude Code in the container
devc mount SRC DST Add a bind mount (host → container)
devc sync [NAME] Sync Claude Code sessions from devcontainers to host
devc self-install Install devc to ~/.local/bin
Note: Use
devc destroyto clean up a project's Docker resources. Removing containers manually (e.g.,docker rm) will leave orphaned volumes and images behind thatdevc destroywon't be able to find.
Claude Code's /insights command analyzes your session history, but it only reads from ~/.claude/projects/ on the host. Sessions inside devcontainer volumes are invisible to it.
devc sync copies session logs from all devcontainers (running and stopped) to the host so /insights can include them:
devc sync # Sync all devcontainers
devc sync crypto # Filter by project name (substring match)Devcontainers are auto-discovered via Docker labels — no need to know container names or IDs. The sync is incremental, so it's safe to run repeatedly.
Drag files from your host into the VS Code Explorer panel — they are copied into /workspace/ automatically. No configuration needed.
To make a host directory available inside the container:
devc mount ~/drop /drop # Read-write
devc mount ~/secrets /secrets --readonlyThis adds a bind mount to devcontainer.json and recreates the container. Existing mounts are preserved across devc template updates.
Tip: A shared "drop folder" is useful for passing files in without mounting your entire home directory.
Security note: Avoid mounting large host directories (e.g.,
$HOME). Every mounted path is writable from inside the container unless--readonlyis specified, which undermines the filesystem isolation this project provides.
By default, devc . uses the prebuilt my-ai-sandbox/devcontainer:local image (requires devc build-image first). For projects that need additional dependencies or customizations, use the --custom flag:
devc . --customThis copies a Dockerfile into .devcontainer/ that extends the base image:
FROM my-ai-sandbox/devcontainer:local
# Add your project-specific customizations hereThe container builds locally each time, allowing you to add project-specific tools, dependencies, or configurations. Edit .devcontainer/Dockerfile after installation to customize.
By default the container has full outbound network. To harden reviews, use iptables (the image includes iptables / ipset).
- Reviewing code that may contain malicious dependencies
- Auditing software with telemetry or phone-home behavior
- Maximum isolation for highly sensitive reviews
Allow Anthropic, OpenAI (Codex), GitHub, and common package hosts—then default-deny the rest:
sudo iptables -A OUTPUT -d api.anthropic.com -j ACCEPT
sudo iptables -A OUTPUT -d api.openai.com -j ACCEPT
sudo iptables -A OUTPUT -d github.com -j ACCEPT
sudo iptables -A OUTPUT -d raw.githubusercontent.com -j ACCEPT
sudo iptables -A OUTPUT -d registry.npmjs.org -j ACCEPT
sudo iptables -A OUTPUT -d pypi.org -j ACCEPT
sudo iptables -A OUTPUT -d files.pythonhosted.org -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT
sudo iptables -A OUTPUT -j DROPTune the allowlist for your workflow (ChatGPT / device flows may need extra hosts).
- Package installs fail unless you allowlist their registries
- Some tools need network you did not anticipate
- DNS may still resolve; block explicitly if you need stricter control
The primary threat this project addresses is Claude Code and Codex running arbitrary commands on your host machine. When bypassPermissions is enabled, Claude executes shell commands, installs packages, and modifies files without confirmation. On a host machine this means it can modify your shell config, rm -rf outside the project directory, or abuse locally stored credentials. The devcontainer confines all of that to a disposable container where the blast radius is limited to /workspace.
The container includes common development tooling so you can do all development work inside it - not just run Claude. The intended workflow is: clone a repository, start the devcontainer, and work entirely within it. If your project needs additional runtimes or tools beyond what's included, either add them to the Dockerfile for repeated use or install them ad-hoc with devc exec.
For the specific boundaries of what is and isn't isolated, see Security Model below. One nuance worth calling out: the devcontainer runtime automatically forwards your host's SSH agent socket (SSH_AUTH_SOCK) into the container. This lets code inside the container authenticate as you over SSH (e.g., git push), but the actual private key material stays on the host and is never exposed to the container.
This setup gives filesystem isolation, not a full formal sandbox.
Isolated: Workspace filesystem (bind-mounted project), processes, and package installs stay in the container.
Not isolated by default: Outbound network (see above), git identity (~/.gitconfig bind-mounted read-only), SSH agent (socket forwarded, keys stay on host), Docker socket (not mounted by default), and anything you add to the workspace.
Claude is configured for bypassPermissions inside the container so it can run commands without per-step confirmation—that is intentional inside this environment, not something you want unchecked on your host.
Codex is intended to be used with similarly permissive approval and sandbox defaults for the workspace inside this container (for example low-friction command execution in devcontainer workflows)—keep stricter Codex policies on machines where the agent can reach your real home directory and projects outside the sandbox.
| Item | Notes |
|---|---|
| Base | Ubuntu 24.04 (Microsoft devcontainers base), Node 22 (fnm), Python 3.13 + uv, zsh |
| User | vscode, passwordless sudo, workdir /workspace |
| Agents | Claude Code; OpenAI Codex in the editor; refresh Claude + Codex CLI with devc upgrade-agents (installs or upgrades @openai/codex) |
| Tools | rg, fd, tmux, fzf, delta, ast-grep, iptables, ipset, … |
| Image | my-ai-sandbox/devcontainer:local — one build, many containers |
| Volumes (per devcontainer id) | Shell history (/commandhistory), ~/.claude, ~/.codex, ~/.config/gh |
Host ~/.gitconfig is mounted read-only for commits; ~/.claude/commands and ~/.codex/commands are optional read-only command folders from the host.
npm install -g @devcontainers/cli- Confirm Docker is running
- Ensure the image exists:
devc build-imagefrom the ai-sandbox-devcontainer clone - Rebuild container:
devc rebuild - Logs:
docker logs $(docker ps -lq)
The gh volume may need ownership fix:
sudo chown -R "$(id -u):$(id -g)" ~/.config/ghPython is managed via uv:
uv run script.py # Run a script
uv add package # Add project dependency
uv run --with requests py.py # Ad-hoc dependency