Guided journey

Give Your Coding Agent Its Own Sandbox

An intermediate journey: isolate an AI coding agent in a container, strip its credentials, restrict network egress, and verify the boundary by testing it.

You walk away with

A coding agent that runs in an isolated workspace, without your credentials, with restricted network access — and a test that proves the boundary holds.

Assume you have

You already run a coding agent on your machine with auto-approved commands, or you want to before you use one on a real project.

Stack used

A container runtime, git worktrees, and whatever secret store you already use. No specific agent required.

The project

Move your coding agent off your personal account and into a workspace you control: its own container, its own branch, only the credentials the task needs, and outbound network access narrowed to the destinations it actually uses. Then try to break out, and fix what still works.

By the end you will have: an image that runs the agent as a non-root user with a minimal environment, a worktree per task, a scoped credential instead of your personal token, an egress allow-list, and a written test that the boundary holds.

Before you start

  • A container runtime installed and working.
  • The agent you use, and its configuration location.
  • How to Sandbox an AI Coding Agent as the reference for the commands. This journey is the order to do it in and the verification at the end.

Milestone — Audit what the agent can reach today

Build: a written list of the files, credentials, and network destinations your agent currently has.

You cannot reduce a blast radius you have not measured. Spend ten minutes finding out how bad the current default is before you change anything.

Do it

  1. Start the agent as you normally do and ask it to print its working directory, its user, and the environment variable names it can see.
  2. List anything sensitive in that environment — API keys, tokens, database URLs, cloud credentials.
  3. Check whether it can read your SSH keys, your shell history, and any .env files outside the project.

Done when you have a list of what is exposed, and you have decided which items should never have been reachable.

Milestone — Choose the isolation level

Build: a decision between a container, a disposable virtual machine, and a remote development environment.

The right level depends on what the agent can do and how much you care about the machine it runs on. Bigger isolation costs a little setup and a little speed.

Do it

  1. If the agent only edits files in one repository and runs its tests, a container with a single worktree mounted is proportionate.
  2. If it runs arbitrary code, installs packages, or touches deployment tooling, prefer a disposable VM or a remote sandbox you can destroy.
  3. Write the choice and why into NOTES.md.

Done when the level is chosen deliberately and you can say what it does not protect against. Hostile code inside the container and your own credentials passed into it are both outside the boundary’s protection.

Milestone — Build an image that has the project’s tools

Build: a container image the agent works inside, without friction.

A sandbox that cannot run the test suite gets turned off within a day. Build the image so the ordinary workflow still works.

Do it

  1. Start from the same base image your project targets, so versions match what you deploy to.
  2. Install the language runtime, the package manager, the test runner, and the database client the project needs.
  3. Bake in a non-root user and switch to it.
  4. Commit the image definition to the repository so it is reproducible and reviewable.

Prompt your agent

Write a Dockerfile for a sandboxed development environment for this
project. It should:

- Use the same base image as production.
- Install the toolchain: runtime, package manager, test runner,
  and the database client.
- Create a non-root user and switch to it.
- Set the working directory to /work.
- Have no credentials baked in, and no SSH keys.
- Include a README comment explaining how to run it.

Do not add anything that only exists to make the agent's life easier.

Done when you can start the container, run the project’s test command inside it, and the tests pass. Docker vs Podman: What’s the Difference? if you have not picked a runtime.

Milestone — Mount a worktree, not your home directory

Build: one worktree per task, mounted into the sandbox and nothing else.

The mount is the blast radius. A container with your home directory inside is a sandbox in name only.

Do it

  1. Create a worktree and a branch for the task before starting the agent.
  2. Run the container with only that worktree mounted, at a known path.
  3. Confirm the main checkout is not visible from inside.

Done when a command inside the sandbox that tries to list your home directory finds nothing. How to Stop Two AI Agents Editing the Same File uses the same primitive when you run more than one agent.

git worktree add ../agent-work -b agent/task-123

docker run --rm -it \
  --user 1000:1000 \
  --cap-drop=ALL \
  --security-opt=no-new-privileges \
  --mount type=bind,src="$PWD/../agent-work",dst=/work \
  -w /work sandbox-image bash

Milestone — Cut credentials to the task

Build: a scoped token the agent can use, and nothing else in its environment.

An agent with your personal token and full network access can reach anything you can. The goal is the smallest credential that lets the task succeed.

Do it

  1. Start the agent with a minimal environment instead of inheriting your shell.
  2. Where it needs a service, mint a short-lived token limited to the specific resource — one repository, one read-only scope.
  3. Prefer a dedicated machine identity over your own account, so revocation does not change your access.
  4. Check the agent’s environment and confirm the only secret present is the scoped one.

Done when the environment contains no personal credential and the task still works. What Is a Non-Human Identity? and the OWASP Non-Human Identity Top 10 explain why these identities need their own lifecycle.

Milestone — Narrow the network

Build: an egress rule that allows the destinations the agent needs and denies the rest.

Open outbound access is how anything the agent reads can leave, and how a fetched instruction can redirect it somewhere unexpected. If the task does not need the network, turn it off.

Do it

  1. List the destinations the work requires: the package registry, the model API, and any service the tests call.
  2. Configure the container network to permit those and deny others — a private network with a proxy, or the runtime’s egress controls.
  3. From inside, confirm an unrelated destination is blocked.

Done when a request to an arbitrary host fails and the legitimate ones succeed.

Milestone — Test the boundary by attacking it

Build: a short script that attempts what the sandbox should prevent.

An untested sandbox is a policy, not a control. Run the checks and repair whatever still succeeds.

Do it

  1. Confirm the user is non-privileged and cannot escalate.
  2. Confirm there is no SSH key, no cloud credential, and no .env outside the worktree.
  3. Attempt to write outside the mounted worktree.
  4. Attempt to reach an arbitrary external host.
  5. Save the commands as a script in the repository, so it is repeatable after an image change.

Done when every check behaves as intended, and the script lives with the project. Securing AI Agents and LLM Features: The Attack Surface You Just Added lists the failure modes worth adding to the script.

# Boundary checks — expect failures for the last three.
whoami
ls ~/.ssh 2>&1
touch /etc/should-not-write 2>&1
curl -s -m 3 https://example.org >/dev/null && echo REACHABLE || echo BLOCKED

Milestone — Keep approvals for irreversible actions

Build: a rule about what the agent may do without asking, and what it must not.

The sandbox bounds damage; approvals prevent it. Decide explicitly which is which, so the answer does not depend on how busy you are.

Do it

  1. Allow reads, edits inside the worktree, and test runs without a prompt.
  2. Require confirmation for anything that deletes data, changes infrastructure, or pushes to a shared branch.
  3. If the agent can use MCP tools, review what those tools can do before enabling auto-approval — What Is MCP (Model Context Protocol) and Why Does It Need Securing? and How to Secure an MCP Server.

Done when the allow-list is written down and you have seen the agent ask for approval on a destructive command. What Is the “Lethal Trifecta” for AI Agents? is the combination to avoid: private data, untrusted instructions, and a channel to send data out.

Milestone — Make it the easy path

Build: a single command that starts the sandboxed agent with the right mounts and environment.

A sandbox that requires remembering six flags will be bypassed. Reduce it to one command.

Do it

  1. Wrap the container invocation in a script committed to the repository.
  2. Have it create the worktree, mount it, and pass only the scoped credential.
  3. Add a line to the project’s agent rules file so the sandboxed path is the documented one — What Is AGENTS.md (and Why Does Your Agent Ignore Your Rules)?.

Done when you have used the script for a full task without dropping back to the unsandboxed path.

Milestone — Land the work through review

Build: a merged branch that went through the same review you would apply to a human’s pull request.

The sandbox keeps the agent contained; it does not tell you whether the change is correct. Review is still the gate.

Do it

  1. Run the full test suite on the branch inside the container.
  2. Review the diff for the usual generated-code failure patterns.
  3. Merge, and remove the worktree.

Done when the change is merged and you know which parts of it you would not have accepted unchanged. How to Review AI-Generated Code Like a Senior Engineer and Journey: Debug and Refactor the Code You Didn’t Write cover the review habit.

Ship checklist

  • You know what the agent could reach before the change.
  • The isolation level is chosen and its limits are written down.
  • The image runs the project’s tests as a non-root user.
  • Only a worktree is mounted; the home directory is not visible.
  • The agent holds a scoped credential, not a personal token.
  • Egress is limited to the destinations the task needs.
  • A boundary-check script exists and passes.
  • Auto-approval covers only non-destructive actions.
  • One command starts the sandboxed agent.
  • The change was reviewed before merging.

Where this journey goes wrong

  • Mounting the project’s parent directory. That is usually home, and it undoes the isolation.
  • Passing the host environment into the container. Every exported secret comes with it.
  • Auto-approving everything because the agent is “in a container”. The container does not cover the credentials you gave it.
  • Leaving egress open. Reading is fine; sending data out is the risk.
  • Treating the sandbox as a substitute for review. Most mistakes stay inside the boundary.
  • A sandbox nobody can start. It gets bypassed within a day.

FAQ

Is auto-approving commands always wrong?

No, but it should be a decision rather than a default. Auto-approval is reasonable inside a sandbox with no credentials, restricted egress, and a disposable workspace, because the blast radius is contained. It is unreasonable when the agent runs as your user with your tokens and your whole home directory mounted, which is the configuration most tools install with.

Does the sandbox replace reviewing the diff?

No. The sandbox bounds what a mistake can reach; review catches mistakes that stay inside the boundary, which is most of them. They answer different questions: the sandbox decides what the agent can touch, and the review decides what you keep.

How much does this slow down everyday work?

Very little once the image exists. The start-up command is one script, and the container caches its layers, so the agent runs at essentially native speed for editing and tests. The tasks that suffer are the ones that quietly relied on ambient access — reading a file outside the project, or using a credential you never scoped.

Share: