Taming the AI: My Paranoid Guide to Running Copilot CLI in a Secure Docker Sandbox

6 min read Original article ↗

I love the new GitHub Copilot CLI. But as someone who's a little paranoid about security, the idea of an AI having deep access to my terminal and file system made me uneasy.

The Copilot CLI gets its usefulness from executing commands, but that requires a level of trust I wasn't fully comfortable handing over. I wanted to use features like --allow-all-tools without feeling like I was handing over the keys to my entire machine.

So I decided to put it in Docker.

I had four goals for what this setup needed to do:

  • Secure isolation: The tool should only see the files in my current project directory. Nothing else.
  • Auto-authentication: It should use my existing gh login without any extra steps.
  • Portability: No global Node.js or npm packages on my host machine.
  • Peace of mind: I want to feel safe enough to let it do its job, even if that means letting it run commands automatically.

After a bit of trial and error (and a lot of debugging), I landed on a solution that met all these goals. The core idea is to run Copilot inside a container, which shrinks the "blast radius" of any potential mistakes.

You're probably thinking, "Wait, if it runs rm -rf ., won't that delete my code?" You'd be right. It would.

The key difference is what "." refers to. Inside the container, it would delete the contents of the /work directory, which is mapped to your current project directory. It can't touch your home directory, your SSH keys, or any other project folder. It's contained. Annoying? Yes. Catastrophic? No.

One thing worth knowing: this cage has open windows for network access. The container shares your host machine's network, so it's not a firewalled environment like a GitHub-hosted runner. Copilot can reach local resources, which is something to keep in mind.

That isolation is what gives me enough comfort to actually use --allow-all-tools. The risk isn't gone, but it's contained to a level I can live with.

The final working Copilot CLI session, showing the banner and the logged-in user.
The final, working setup! It took a while to get here, but it was worth it.

The complete solution is hosted on GitHub at https://github.com/GordonBeeming/copilot_here. The setup consists of two files: a Dockerfile to build the environment and an entrypoint.sh script to handle user permissions.

Here's the Dockerfile:

And the entrypoint.sh script:

Understanding the modes and features

The setup has two execution modes and a bunch of image variants.

Safe mode (copilot_here) - Always asks for confirmation before executing commands. Good for everyday work where you want to stay in control.

YOLO mode (copilot_yolo) - Auto-approves all tool usage without prompting. Useful for trusted workflows, but be aware it will run commands without asking.

All functions support switching between Docker image variants using flags:

  • No flag - Base image (Node.js, Git, basic tools)
  • --dotnet (-d) - .NET image (includes .NET 8, 9 & 10 SDKs)
  • --dotnet8 (-d8) - .NET 8 image (includes .NET 8 SDK)
  • --dotnet9 (-d9) - .NET 9 image (includes .NET 9 SDK)
  • --dotnet10 (-d10) - .NET 10 image (includes .NET 10 SDK)
  • --playwright (-pw) - Playwright image (includes browser automation)
  • --dotnet-playwright (-dp) - .NET + Playwright image (includes browser automation)
  • --rust (-rs) - Rust image (includes Rust toolchain)
  • --dotnet-rust (-dr) - .NET + Rust image
  • -h or --help - Show usage help and examples (Bash/Zsh) or -h / -Help (PowerShell)
  • --no-cleanup - Skip cleanup of unused Docker images (Bash/Zsh) or -NoCleanup (PowerShell)
  • --no-pull - Skip pulling the latest image (Bash/Zsh) or -NoPull (PowerShell)

Both modes check your GitHub token scopes and warn if the token has more permissions than needed. They also clean up unused Docker images tagged with the project label automatically.

Both platforms have a one-liner installer.

For Linux/macOS (Bash/Zsh):

For Windows (PowerShell):

This downloads the script and configures your PowerShell profile.

To update to the latest version:

This downloads the latest CLI binary, shows you what version changed, and reloads the updated functions in your current shell.

For manual installation or a full list of options, visit the GitHub repository. The repo has docs on all flags, the image variants, Airlock network isolation config, and copy-paste install blocks if you prefer that approach.

Start a full chat session with the welcome banner:

Pass a prompt directly for a quick response.

Safe mode (asks for confirmation before executing):

YOLO mode (auto-approves execution):

As the project grew, I kept running into cases where the base image wasn't enough. .NET projects need SDKs. Browser tests need Chromium. So I added specialized variants on top of the base image.

Base image (latest): Node.js 20, Git, and basic tools. Works for general scripting and anything that doesn't need a specific runtime.

.NET image (dotnet): Adds .NET 8.0 and 9.0 SDKs with ASP.NET Core runtimes and ICU libraries. Good for .NET work when you don't need browser testing on top.

.NET + Playwright image (dotnet-playwright): Everything in the .NET image, plus Playwright 1.56.0 and Chromium with all its dependencies. About 500-600MB larger than the base image because of the Chromium binaries, so only use it when you need it.

You switch between variants with flags like -d for .NET or -dp for .NET + Playwright, rather than manually editing image names.

The functions automatically remove unused copilot_here images (filtered by the project=copilot_here label) and keep only the one you're currently using. This stops old image versions from quietly eating your disk space.

If you want to skip the cleanup for faster startup, use --no-cleanup (or -NoCleanup on PowerShell). You can also skip pulling the latest image with --no-pull (or -NoPull) if you need to move fast and already have the image locally.

Conclusion: security and convenience can coexist

I reach for Docker a lot when I'm evaluating new CLI tools. It's not just for deploying apps; it's genuinely useful for building a sandbox around things you don't fully trust yet.

This setup doesn't make me reckless. I still pay attention to the projects I run it in. But it lowers the stakes enough that I can actually let the tool do what it's designed to do. In my daily workflow I keep both versions installed: copilot_here for normal use, and copilot_yolo for trusted projects where I want speed over caution.

The image variants mean I'm not stuck picking between "works for my project" and "doesn't bloat my Docker storage". -d for .NET, -dp when I need browser tests. Simple enough that I actually use it instead of second-guessing which image to reach for.

All the source code is at https://github.com/GordonBeeming/copilot_here. Give it a try.