Sandboxing Local AI Coding Agents: Containers, VMs and Separate Users
- Author
- Vishal Maurya
- Published on
- Reading time
- 5 min read
Overview
You install an AI coding agent that can run shell commands, edit files, and install packages. On your laptop it inherits your permissions: your home directory, your SSH keys, your cloud credentials, and your network. Most of the time that is fine. The risk is the occasional bad command, a malicious dependency, or text in a file or web page that steers the agent somewhere you did not intend.
This guide walks through a simple threat model and the isolation options, so you can pick a sandbox proportional to the risk.
1. Write Down the Threat Model
Be specific about what you are protecting against:
Accidents: agent deletes files, rewrites the wrong repo, runs a destructive command
Exfiltration: agent or a dependency reads secrets and sends them out
Injection: instructions hidden in a README, issue, or web page change agent behavior
Persistence: something modifies shell config, cron, or git hooks outside the project
Most developers need protection from accidents and credential exposure first. Defending against a determined attacker is a harder problem and needs stronger isolation.
2. Compare the Isolation Options
Separate user account. A dedicated OS user with no access to your main home directory. Cheap and simple, and it protects your personal files and keys. It shares the kernel and the network, so it offers limited protection against a hostile process.
Container. Good balance for day-to-day work. You mount only the project directory, drop privileges, and restrict the network. Containers share the host kernel, so they are not a hard security boundary, and mounting the Docker socket or running privileged containers largely defeats the purpose.
Virtual machine. A separate kernel and a stronger boundary. Better when you run untrusted code or want a throwaway environment. Costs more in setup, resources, and file sharing friction.
Pick the lightest option that matches your threat model, and prefer a VM when the code or inputs are untrusted.
3. Limit the Filesystem
Give the agent a working copy of the project, not your home directory. Work on a branch or a fresh clone so a bad edit is easy to discard.
Avoid mounting ~/.ssh, ~/.aws, browser profiles, or shell history. If the agent needs git access, prefer a clone it can modify and push through a separate, narrowly scoped credential.
4. Limit the Network
Many tasks need only a package registry and the model API. If you can, allow only those destinations. With plain Docker, the simplest controls are no network at all or a custom network with egress rules enforced outside the container. Check your environment's documentation for how to enforce an allowlist, since the right mechanism depends on your setup.
Blocking the network entirely is the strongest option for work that does not need it, such as refactoring and running local tests against vendored dependencies.
5. Handle Secrets Deliberately
- Do not put long-lived production credentials in the environment the agent can read.
- Use short-lived or least-privilege tokens, scoped to one repository or one environment.
- Keep
.envfiles with real secrets out of the mounted directory, or use fake values for local work. - Assume anything the agent can read could appear in its context and logs.
Rotate a credential if you suspect it was exposed.
6. Use Approval Modes Wisely
Most agents let you choose how much runs without confirmation. Treat that as a second layer, not a replacement for isolation. Require approval for commands that delete, install globally, touch the network, or run outside the project. Auto-approval is far safer inside a sandbox than on your main machine, because the blast radius is smaller. Read your tool's documentation to see exactly what each mode permits.
7. A Practical Docker Example
docker run --rm -it \
--name agent-sandbox \
--user 1000:1000 \
--read-only \
--tmpfs /tmp \
--cap-drop ALL \
--security-opt no-new-privileges \
--pids-limit 256 \
--memory 4g \
-v "$PWD":/workspace \
-w /workspace \
node:22 bash
This runs as an unprivileged user, drops Linux capabilities, blocks privilege escalation, limits processes and memory, and mounts only the current project. The root filesystem is read-only, so tools that write caches or install packages need writable paths such as extra volumes; adjust to your toolchain. Add --network none for offline work.
Never add --privileged, never mount /var/run/docker.sock, and be careful with bind mounts that include dotfiles. On macOS and Windows, containers run inside a Linux VM, which adds some separation but does not change these rules.
Conclusion
Start with a threat model, then choose the lightest isolation that covers it: a separate user for basic protection, a locked-down container for routine work, a VM for untrusted code. Combine that with scoped credentials, limited network access, and sensible approval settings.
If you want help setting up a safe development environment for AI-assisted workflows in your team, I can help. Contact me.