Secure Git Automation for Claude Code with Dev Containers and Fine-Grained PATs
Leverage autonomous AI agents securely using a dedicated GitHub machine user account with fine-grained, project-scoped PATs to automate Claude Code in workspace isolated VS Code Dev Containers.

Overview
AI Agents like Claude Code require terminal access to run builds, tests, and git commands. Running them directly on your host machine opens you up to the possibility of an agent executing a rogue script, prompt injection, host system file deletion or running commands that could access secrets saved in ~/.aws or ~/.ssh. Allowing them access to your personal GitHub credentials means the agent can read/write to any of your GitHub repositories.
While AI Agents offer an incredible productivity boost, they are not without risk. To balance security against velocity, it helps to establish four key isolation boundaries:
Host Isolation: The agent operates inside a Docker container. The host file system, local SSH keys, and personal credentials should never be mounted or exposed.
Identity Isolation: The agent acts as a dedicated GitHub "machine user" and member to the Organization hosting the repo.
Credential Isolation: Git operations use an Organization-scoped Fine-Grained PAT restricted to a single repository, scoped to Contents and Pull Requests read/write access.
Data Isolation: Claude Code’s session data (
.claude/) is isolated inside a named Docker volume and ignored by Git.
We can run AI Agents reliably and with some safety measures by implementing these isolation boundaries and pairing them with these tools:
Dedicated GitHub Machine User to separate agent identity from human accounts.
Organization-Scoped Fine-Grained PAT to restrict repository access to minimum required permissions.
VS Code Dev Containers to provide a consistent, sandbox environment that provides a layer of isolation to host resources.
Pre-requisites
VS Code Dev Containers extension installed. Search for it on the marketplace.
Docker Desktop or Orbstack (MacOS) installed
Machine User & Fine-Grained Token Pattern
Organization & Machine User Setup
If you haven't already:
Create a free GitHub Organization and transfer your target repository into it.
Ensure Fine-Grained Personal Access Tokens are enabled under Organization Settings.
Invite your dedicated Machine User to the Organization and grant it Write / Collaborator access to the target repository. If you're a Gmail user you can setup your machine user with an alias using:
your_gmail+machine_user_name@gmail.com
Issuing the Fine-Grained PAT
Log into GitHub as your Machine User and navigate to Settings > Developer Settings > Personal Access Tokens > Fine-grained tokens. Generate a token using these settings:
Setting | Value | Why It Matters |
Resource Owner | Organization | Ensures the token is governed by organizational policies. |
Repository Access | Selected repositories | Prevents the token from accessing any other repos in the Org. |
Repository Permissions | Contents: | Grants only what Claude Code needs to push code and open PRs. If you want Claude to create issues, enable those also. |
Machine User Token Helper Script
Store Tokens in a Secure Host Folder
Keep all project tokens centrally on your host outside of any Git repository. Name the tokens after your repo-specific names:
~/.gh-tokens/
├── project-a.token
├── project-b.token
└── project-c.token
Create a Shell Alias on Your Host (~/.zshrc / ~/.bashrc)
Add a simple launcher helper function to your host shell profile. Update the GH env vars to match the name of your machine user created in the previous step.
# Dev container token helper
dev-agent() {
local project_name=$(basename "$PWD")
local token_file="$HOME/.gh-tokens/${project_name}.token"
if [ -f "$token_file" ]; then
export GH_TOKEN=$(cat "$token_file")
export GIT_AUTHOR_NAME="machine-username"
export GIT_AUTHOR_EMAIL="machine-username@users.noreply.github.com"
echo "Loaded project-scoped credentials for ${project_name}"
else
echo "Warning: No token file at ${token_file}. Launching with local host inherited credentials."
unset GH_TOKEN; unset GIT_AUTHOR_NAME; unset GIT_AUTHOR_EMAIL
fi
code .
}
dev-agent-cli function by installing the dev containers cli with npm install -g @devcontainers/cli and replacing the code command with devcontainer up --workspace-folder .Setting Up the Dev Container
Create devcontainer.json
Save the following configuration as .devcontainer/devcontainer.json in your repository:
{
"name": "Claude Agent Workspace (Base Bookworm)",
"build": {
"dockerfile": "Dockerfile"
},
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {},
},
// Drop capabilities and block privilege escalation
"runArgs": [
"--cap-drop=ALL",
"--security-opt=no-new-privileges"
],
"mounts": [
"source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume"
],
"containerEnv": {
"CLAUDE_CONFIG_DIR": "/home/vscode/.claude"
},
"remoteEnv": {
"GH_TOKEN": "${localEnv:GH_TOKEN}",
"GIT_AUTHOR_NAME": "${localEnv:GIT_AUTHOR_NAME}",
"GIT_AUTHOR_EMAIL": "${localEnv:GIT_AUTHOR_EMAIL}"
},
"customizations": {
"vscode": {
"extensions": [
"anthropic.claude-code",
"shd101wyy.markdown-preview-enhanced"
]
}
},
"postCreateCommand": "git config --global user.name \"$GIT_AUTHOR_NAME\" && git config --global user.email \"$GIT_AUTHOR_EMAIL\" && gh auth setup-git",
"remoteUser": "vscode",
}
The
claude-code-config-${devcontainerId}mount maps the container path to a persistent, named Docker volume.The
${devcontainerId}keeps credentials scoped to the Docker volume of the launched container. Moving or renaming the local project folder, will cause it to evaluate a new hash, creating a new named volume that forces re-authentication.The
CLAUDE_CONFIG_DIRenv var stores credentials, history and config files instead of the default~./claudedirectory created by the root user.
Create Dockerfile
Save the following simple Dockerfile under .devcontainer/ in your repository:
FROM mcr.microsoft.com/devcontainers/base:bookworm
# Pre-create the directory under the non-root user so named volumes inherit ownership
USER vscode
RUN mkdir -p /home/vscode/.claude
You can use this as a base to iterate on depending on your workspace requirements.
Running as
vscode(a non-root user) in the container allows you to runclaude --dangerously-skip-permissionsfor fully autonomous workflows. However, as mentioned below, running AI Agents in Dev Containers still comes with risks.
Launch the agent Dev Container
💡 For a working example of a Full-Stack Claude Agent Workspace, you can check out my Dev Container setup here.
Whenever you start work on a project:
cd ~/code/project-a
dev-agent
# Working example:
❯ cd ai-dev-tools-zoomcamp-2026/
❯ dev-agent
Loaded project-scoped credentials for ai-dev-tools-zoomcamp-2026
Zero sensitive files in the workspace: There is no
.envrc,.env, or configuration file inside the project for the agent to inspect.Automatic project matching: dev-agent automatically picks up
~/.gh-tokens/ai-dev-tools-zoomcamp-2026.tokenbased on the folder name, setsGH_TOKENin that terminal session only, and opens VS Code.Container Isolation:
${localEnv:GH_TOKEN}indevcontainer.jsonpasses the token into the container environment seamlessly.
Verification Inside the Container
Once VS Code builds and opens the Dev Container, launch an integrated terminal inside the container and test the security boundaries:
whoami && id
sudo whoami
# Expected Output: vscode for the user identity, followed by a permission error on sudo.
gh auth status
gh api user --jq '.login'
# Expected Output: gh auth status confirms token authentication, and the API query returns the GitHub machine username.
git fetch origin
git var GIT_AUTHOR_IDENT
# Expected Output: Success. git fetch completes without prompt, and Git outputs the machine user name and email.
git clone https://github.com/your-org/another-private-repo.git /tmp/test-repo
# Expected Output: Failure. Returns HTTP 403 (Forbidden) or HTTP 404 (Not Found), confirming that the token cannot reach or manipulate repositories outside its explicit scope.
Conclusion
While Fine-Grained PATs prevent agents from deleting or reading your repos, and Dev Containers provide a helpful layer of workspace isolation, your host system can still be exposed to unpredictable code execution by AI Agents like Claude Code.
Dev Containers share the host kernel by design. If an AI agent encounters a malicious payload, prompt injection, or executes an unintended command, it is not prevented from:
Reading or modifying files mounted directly from your host filesystem.
Reaching out to arbitrary external IP addresses/URLs on the open internet.
Attempting container escapes via host IPC bridges or exposed Docker sockets.
While Dev Containers don't offer complete host isolation, they do provide a valuable layer of workspace isolation through reproducible, containerized environments. Combine them with a dedicated machine user and scoped, fine-grained PAT's and you get better visibility over your AI Agent's commits without compromising your developer experience.
Additional Resources
Claude Code DevContainer by Trail of Bits
Further Exploration
Restricting Network Access via
iptables/ Egress Filtering: Applying customdevcontaineriptables rules or network proxies to restrict outbound URL access to whitelisted endpoints (e.g., only allowing traffic to Anthropic APIs and specific GitHub domains). Ref Anthropic's iptables example.Hardware-Level Isolation with Dedicated Virtual Machines: Running Docker inside isolated local VMs (using tools like Lima on macOS, isolated WSL2 distros on Windows, or QEMU/KVM).



