Model or dataset
trailofbits/claude-code-devcontainer avatar
trailofbits/claude-code-devcontainer

claude-code-devcontainer: running Claude Code in bypass mode without exposing the host

Sandboxed devcontainer for running Claude Code in bypass mode safely. Built for security audits and untrusted code review.

958 stars107 forksShellApache-2.0

At a glance

What is it?
This devcontainer from Trail of Bits runs Claude Code with `bypassPermissions` enabled inside a disposable container, so an agent that executes any command without confirmation stays confined to a project directory. The readme is unusually blunt about which workflow breaks that guarantee.
Who is it for?
This devcontainer suits a security auditor or engineer who needs an agent to move freely through untrusted code, and it is the wrong tool for anyone who wants the VS Code editing experience on untrusted code, since the readme states container code can execute commands on the host through that path by design.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 56 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why bypass mode needs a filesystem boundary

The devcontainer runs Claude Code with `bypassPermissions` enabled, and the readme explains the motivation directly. Running Claude with `bypassPermissions` on your host machine is risky because it can execute any command without confirmation. The container provides filesystem isolation, so unrestricted Claude reaches only your project directory and a disposable container, not the rest of your host.

That is the whole thesis of the project, and it explains why it exists at Trail of Bits for security audit workflows. The intended users are people whose job involves running an agent over code they did not write, where the agent needs to be able to build, test and modify without stopping for confirmation on every command.

Four use cases are listed. Security audits mean reviewing client code without exposing your host. Untrusted repositories mean exploring an unknown codebase safely. Experimental work means letting Claude modify code freely in isolation. Multi-repo engagements mean working on several related repositories, which the second container pattern is built for.

The project is licensed under Apache-2.0 with the licence text in the LICENSE file, the primary language is Shell, and the last push to the default branch was on 2026-08-28. The repository has no GitHub releases, so there is no tagged artefact to point at.

The repository contents show the shape of it: a `Dockerfile`, a `devcontainer.json`, an `install.sh`, a `post_install.py`, a `.zshrc` and a `.claude/` directory. It is a template you install, not a service you run.

The VS Code path is explicitly not recommended for untrusted code

The readme draws a line that is worth reading twice, because it is the kind of warning most projects bury.

For the VS Code and Cursor pattern, it says plainly: not recommended for untrusted code. Container code can execute commands on your host through this path, by design.

The reason is structural. The Dev Containers extension mounts the project folder into the container, and the extension's own integration means the container has a route back to the host for the editor to function. Any code that runs inside the container, including code an agent writes, can use that route. The isolation the container provides against the rest of your filesystem is therefore not sufficient on that path, because the editor path is a deliberate bridge.

So the readme splits the workflows by trust level rather than by convenience. The terminal pattern, `devc .` and `devc shell`, is the one to use with untrusted code. The VS Code and Cursor path is fine when you trust the repository, where the convenience of the integrated editor is worth more than the stronger boundary.

If you do take the VS Code path, the readme lists the setup. You install the Dev Containers extension, `ms-vscode-remote.remote-containers` for VS Code or `anysphere.remote-containers` for Cursor, then either run `devc .` or clone the template into `.devcontainer/`, open your project folder in the editor, and use the command palette to reopen in container.

Two container patterns, one per engagement shape

The readme offers two patterns, and the difference is about how many repositories you are working on at once.

Pattern A is the per-project container. Each project gets its own container with independent volumes, and the readme calls it best for one-off reviews or when you need isolation between projects. The commands are short: clone the untrusted repository, change into it, run `devc .` to install the template and start the container, then `devc shell` to open a shell in it.

Pattern B is the shared workspace container. A parent directory holds the devcontainer configuration, and you clone several repositories inside it, with shared volumes across all of them. The readme calls this best for client engagements, related repositories or ongoing work.

bash
# Create workspace for a client engagement
mkdir -p ~/sandbox/client-name
cd ~/sandbox/client-name
devc .          # Install template + start container
devc shell      # Opens shell in container

# Inside container:
git clone <client-repo-1>
git clone <client-repo-2>
cd client-repo-1
claude          # Ready to work

Pattern B is the one that matters for a consultancy. The parent directory becomes the boundary, and the audit workspace contains only the repositories the engagement covers. The tradeoff is that the isolation is shared across those repositories, so one repository's compromise reaches the others in the same workspace.

The `devc` command is a helper the template installs, and its lifecycle verbs are documented as a block.

bash
devc .              Install template + start container in current directory
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 cp SRC DST     Copy a path from the container to the host
devc template DIR   Copy devcontainer files to directory
devc self-install   Install devc to ~/.local/bin
devc update         Update devc to the latest version

One note in that list is operational but easy to miss. The readme says to use `devc destroy` to clean up a project's Docker resources, because removing containers manually, for example with `docker rm`, leaves orphaned volumes and images behind that `devc destroy` will not be able to find.

Token auth replaces the interactive wizard in containers

Claude Code's onboarding wizard keeps appearing in containers even when valid credentials exist, and the readme names the upstream issue for that behaviour, issue 8938 in the Claude Code repository.

The workaround is a token based handshake. On the host, once, you generate a token, export it as an environment variable, and rebuild the container.

bash
claude setup-token                          # run on host, one-time
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
devc rebuild                                # rebuilds with token

The token is forwarded into the container, and on each container creation `post_install.py` runs a one-shot auth handshake so `claude` starts without the login wizard. If you do not set a token, the interactive login flow works as before.

This matters for headless servers, which the readme names as the primary case. On a machine with no browser and no interactive terminal, an agent that cannot get past the wizard is simply broken, and the token path removes that dependency.

It also has a security shape you should think about. The token is an account level credential for Claude Code, and `devc rebuild` forwards it into the container. In the Pattern B shared workspace, that token is present in every container in the workspace, because the workspace shares volumes and the agent runs with the permissions you granted it. The token's scope is what limits the damage, not the container.

Session sync copies container-authored text onto the host

Claude Code's `/insights` command analyses session history, but it only reads from `~/.claude/projects/` on the host. Sessions inside devcontainer volumes are invisible to it, so the readme adds a sync mechanism.

bash
devc sync              # Sync all devcontainers
devc sync crypto       # Filter by project name (substring match)

The copy is done from all devcontainers, running and stopped, and devcontainers are auto-discovered via Docker labels, so you do not need to know container names or identifiers. The sync is incremental, so it is safe to run repeatedly.

The readme attaches a security note that deserves attention. This copies container-authored data onto your host, so it prompts first, and `--trusted` skips the prompt. Only `*.jsonl` logs are copied, and always under a `-devcontainer-<project>` key, so a container cannot plant files elsewhere in `~/.claude/projects/`. The transcripts are still container-authored text that a later host session will read.

That last sentence is the important one. The path containment limits where files land, not what they say. The container produced the text, and a host side session will read it as instructions context. For an audit workflow where the container is processing hostile input, that is a channel worth thinking about before you enable the sync on a machine with credentials.

The image is built for agent work, and it carries network tools

The Dockerfile shows what the container actually contains, and the choices are informative.

The base is Microsoft's devcontainer base image for Ubuntu 24.04, pinned by digest, and the image is layered on top of a pinned `ghcr.io/astral-sh/uv` stage so that uv is copied in rather than installed at build time. The comment says the base is chosen for better devcontainer integration.

Two packages are installed explicitly for Claude Code sandboxing support: `bubblewrap` and `socat`. The rest is a developer toolchain, `fd-find`, `ripgrep`, `tmux`, `zsh`, `build-essential`, `jq`, `nano`, `unzip` and `vim`, plus `git-delta` and `fzf` fetched from GitHub releases with architecture handling for amd64 and arm64.

The set that stands out is the network tooling: `dnsutils`, `ipset`, `iptables` and `iproute2`, installed with the comment that they are for security testing. An audit workflow needs to resolve names, inspect routes and manipulate packet filtering, and most general purpose images would not carry those.

There is a `renovate.json` at the top level and inline renovate annotations in the Dockerfile for the pinned dependencies, which is the mechanism that keeps those pins moving. The repository also has a `.pre-commit-config.yaml` style layout with a `.dockerignore` and a `.gitignore`.

For the terminal workflow, the readme also asks you to install the devcontainers CLI globally and clone the template to `~/.claude-devcontainer`, then run `~/.claude-devcontainer/install.sh self-install`.

bash
npm install -g @devcontainers/cli
git clone https://github.com/trailofbits/claude-code-devcontainer ~/.claude-devcontainer
~/.claude-devcontainer/install.sh self-install

Where this devcontainer is the wrong tool

The first case is a workflow that needs the editor. If you want to open an untrusted repository in VS Code or Cursor and have the agent work in the same window, this setup explicitly does not recommend it, because container code can execute commands on your host through that path by design. The alternative in that situation is a real virtual machine, which gives you a boundary the editor integration does not break.

The second case is code you trust. The whole design is aimed at untrusted code, and the cost of the container is real: file system performance depends on the mount type, and the readme spends a section on tuning Colima on Apple Silicon, because the defaults are QEMU with sshfs. It recommends `--vm-type vz` for Apple's Virtualization framework and `--mount-type virtiofs` for file I/O that is five to ten times faster than sshfs.

bash
colima stop && colima delete

colima start \
  --cpu 4 \
  --memory 8 \
  --disk 100 \
  --vm-type vz \
  --vz-rosetta \
  --mount-type virtiofs

If your repositories are your own, that tuning is work you did not need.

The third case is a macOS user on Intel hardware, where the `--vz-rosetta` flag has no meaning, and the third case is any environment without Docker, since the prerequisites list Docker Desktop, OrbStack or Colima, and Colima itself needs a one-time `brew install colima docker && colima start`.

The fourth case is a requirement for audit trails that survive the container. `devc destroy` removes the container, its volumes and its image, which is exactly what you want for an engagement and exactly what you do not want if the record of what the agent did needs to be kept.

Editorial conclusion

This devcontainer suits a security auditor or engineer who needs an agent to move freely through untrusted code, and it is the wrong tool for anyone who wants the VS Code editing experience on untrusted code, since the readme states container code can execute commands on the host through that path by design. Before adopting it, read the threat model section and stick to the terminal pattern with `devc`, and remember that `devc sync` copies container-authored transcripts onto your host, so the isolation is weaker than the container boundary suggests once you use it.

Frequently asked questions

What does the claude-code-devcontainer do?

It is a containerized development environment for running Claude Code with `bypassPermissions` enabled. The container provides filesystem isolation so an unrestricted agent reaches only the project directory and a disposable container rather than the rest of the host.

Can I use this with VS Code or Cursor on untrusted code?

No. The readme marks the VS Code and Cursor pattern as not recommended for untrusted code, because container code can execute commands on your host through that path by design. Use the terminal pattern with `devc` instead.

How does headless authentication work?

Run `claude setup-token` on the host, export the result as `CLAUDE_CODE_OAUTH_TOKEN`, and run `devc rebuild`. The token is forwarded into the container and `post_install.py` performs a one-shot auth handshake so `claude` starts without the interactive wizard.

What does devc sync do and is it safe?

It copies session logs from all devcontainers, running and stopped, to the host so Claude Code's `/insights` command can read them. It prompts before copying, `--trusted` skips the prompt, only `*.jsonl` logs are copied and always under a `-devcontainer-<project>` key, and the readme notes the transcripts are still container-authored text a later host session will read.

Which container patterns does the project support?

Pattern A gives each project its own container with independent volumes, suited to one-off reviews. Pattern B puts the devcontainer configuration in a parent directory and clones several repositories inside it with shared volumes, suited to client engagements and related repositories.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. trailofbits/claude-code-devcontainer on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/trailofbits-claude-code-devcontainer.svg)](https://hysenlabs.com/projects/trailofbits-claude-code-devcontainer)

Was this useful?