DEV Community

Claude code
Claude code

Posted on

Claude Code in CI/CD: Sandboxing Strategies That Actually Contain the Blast Radius

Claude Code in CI/CD: Sandboxing Strategies That Actually Contain the Blast Radius

Claude Code CI/CD sandboxing is the practice of running Anthropic's Claude Code agent inside isolated execution environments — Docker containers, network-restricted namespaces, or ephemeral VMs — during automated pipeline jobs, so that if the agent takes an unintended action, the damage is bounded to the sandbox and cannot propagate to production systems, source repositories, or credential stores.

That definition matters because the threat model for unattended Claude Code runs is materially different from interactive sessions. When a developer runs Claude Code locally, they are sitting in front of a terminal, reviewing each file diff, and can hit Ctrl-C the moment something looks wrong. In a CI job, there is no human in the loop. The agent runs to completion, and whatever it touches, it touches. That asymmetry is why sandboxing deserves its own engineering treatment, not just a checkbox in your security review.

Why Unattended Runs Carry Disproportionate Risk

Prompt injection attacks are the clearest illustration of the problem. Researchers at security firm Invariant Labs demonstrated in 2024 that indirect prompt injection — where malicious instructions are embedded in files, issue bodies, or dependency READMEs that the agent reads during a task — can redirect an LLM agent's behavior without any interaction from the operator. In a CI context, that means a poisoned dependency or a crafted PR description could instruct Claude Code to exfiltrate a secret, push a backdoored commit, or delete build artifacts. Anthropic's own Claude Code security documentation explicitly flags untrusted repository content as an attack surface.

The second risk is credential exposure. CI environments accumulate secrets: AWS keys, npm tokens, GitHub PATs, database passwords. By default, every environment variable in the runner is visible to every process in the job. If Claude Code is invoked with broad filesystem access in that environment, a misbehaving tool call or injected instruction has everything it needs to exfiltrate credentials to an external endpoint.

Docker-Based Claude Code CI/CD Sandboxing: The Right Defaults

Docker is the most practical isolation layer for most teams. The key is not simply running Claude Code inside a container — it's configuring that container to be hostile to lateral movement.

Volume Mounts

Mount only the directories the agent actually needs. If the task is "fix failing tests in the src/ directory," mount only that directory read-write. Mount everything else read-only, or don't mount it at all. A common mistake is bind-mounting the entire repository root because it's convenient. That convenience also gives the agent access to .env files, SSH keys in ~/.ssh, and anything else that landed in the working tree.

docker run --rm \
  -v $(pwd)/src:/workspace/src:rw \
  -v $(pwd)/tests:/workspace/tests:rw \
  -v $(pwd)/package.json:/workspace/package.json:ro \
  --network none \
  claude-code-runner

Enter fullscreen mode Exit fullscreen mode

--network none is aggressive but correct for tasks that should not require internet access. If Claude Code needs to install packages, use a two-phase approach: resolve and cache dependencies in a prior build step, then run the agent with the cache mounted and the network disabled.

Egress Filtering

For tasks where network access is genuinely required, prefer an allow-list egress policy over blocking all traffic. Tools like iptables rules, Cilium network policies in Kubernetes, or a sidecar proxy (Squid, mitmproxy) let you permit traffic only to specific registries or APIs. The operational overhead is real, but so is the value: a compromised agent that attempts to POST secrets to an external endpoint will fail at the network layer rather than succeed silently.

Credential Exclusion

Never pass your full CI environment into the container with --env-file .env or -e *. Pass only the variables the agent's specific task requires, and rotate those credentials to short-lived tokens where your provider supports it. AWS IAM roles for GitHub Actions, Google Workload Identity Federation, and Vault's dynamic secrets are all preferable to static API keys that survive beyond a single job run.

Git Worktrees Keep Claude Code Off Your Main Working Directory

Even before you reach the container layer, you can reduce blast radius at the Git level. git worktree add creates a second checked-out working tree from the same repository at a different path. Run Claude Code inside that worktree, and any file modifications it makes are isolated from your primary working directory. If the agent does something unexpected — deletes a file, modifies a config it shouldn't have touched — you discard the worktree without touching the main branch.

git worktree add /tmp/claude-task-$(date +%s) HEAD
cd /tmp/claude-task-...
claude --task "refactor auth module"
# review changes, then either cherry-pick or discard
git worktree remove /tmp/claude-task-...

Enter fullscreen mode Exit fullscreen mode

Worktrees also make code review easier. The diff is scoped to what Claude Code actually modified in its isolated directory, not interleaved with your other in-progress work. Combine a worktree with a Docker mount, and the agent's filesystem view is both sandboxed and scoped.

Credential Scoping in CI: Masked Variables vs. OAuth Login

CI platforms like GitHub Actions, GitLab CI, and CircleCI all support secret masking, which prevents the raw value of a secret from appearing in job logs. Masking is necessary but not sufficient. Masking stops a secret from being printed; it does nothing to stop a process from reading the variable and sending it over the network.

The stronger approach is to scope credentials to the minimum surface. For Claude Code specifically:

  • Use an Anthropic API key scoped to a service account with no additional permissions in your organization.

    • If your task requires GitHub access, generate a short-lived GitHub App installation token at the start of the job (gh app token), pass it explicitly, and let it expire — typically within one hour.
    • Avoid using OAuth login flows in CI. Browser-based OAuth requires interactive consent and produces long-lived credentials stored in a local config file. In a CI container, that config file persists for the lifetime of the job and is accessible to every process in it.

At Claude Code, we've seen teams inadvertently persist OAuth tokens in Docker layer caches because the claude login step was included in the image build rather than injected at runtime. That is a credential leak waiting to happen. Run authentication at job start, not image build time, and ensure credential files are written to a tmpfs mount or an ephemeral volume that is destroyed with the container.

Kubernetes Sandboxing for Claude Code CI/CD Pipelines

If your CI runs on Kubernetes, you have additional primitives worth using. Pod Security Admission (PSA) with the restricted profile blocks privilege escalation and requires non-root execution. A dedicated ServiceAccount with no RBAC bindings prevents the agent from calling the Kubernetes API. seccompProfile: RuntimeDefault restricts the syscalls available to the process — relevant because some prompt injection attack chains depend on spawning subprocesses or making unusual syscalls to break container boundaries.

Resource limits (cpu and memory in resources.limits) also matter. An agent stuck in a loop consuming unbounded CPU or memory can destabilize neighboring workloads. Set conservative limits and treat out-of-memory kills as a signal to investigate what the agent was doing, not just a transient failure to retry.

For teams looking to build consistent policy across multiple pipelines, the Claude Code product overview covers how governance and access controls integrate into larger deployment workflows, and the Claude Code documentation provides reference configuration for common CI provider integrations.

What a Minimal Secure Configuration Looks Like

Pulling the above together: a production-grade Claude Code CI job should run in a Docker container with a read-only filesystem except for a scoped worktree mount, no network access or an explicit egress allow-list, only the environment variables required for the specific task, and a non-root user. The job should generate a short-lived API key at start and invalidate or expire it at completion. Logs should be collected and reviewed — not just pass/fail status, but the full agent action trace — so you can audit what the agent actually did.

None of this is exotic. Most of it is standard CI hardening applied specifically to an agentic workload. The difference is that Claude Code can take a wider range of actions than a typical build script, which means the consequence of a misconfiguration is larger. Treat it accordingly.

Frequently Asked Questions

Is it safe to run Claude Code with --dangerously-skip-permissions inside a Docker container?

Conditionally. --dangerously-skip-permissions removes Claude Code's own internal guardrails that prompt for user confirmation before taking destructive actions. Inside a properly sandboxed container — non-root user, read-only mounts except for the task directory, no network or restricted egress — the Docker layer provides compensating controls. But if your container is misconfigured (privileged mode, host network, broad volume mounts), skipping permissions makes a bad situation worse. Audit your container configuration before relying on this flag in production pipelines. Anthropic's documentation explicitly states this flag is intended for containerized use cases only.

How do I prevent Claude Code from inheriting production credentials in a CI job?

Inject only the credentials the specific task requires, and inject them at runtime rather than baking them into the image. Use your CI platform's secret mechanism (GitHub Actions secrets, GitLab CI variables, etc.) to expose only the named variables needed. For cloud credentials, prefer short-lived tokens from OIDC federation (AWS, GCP, Azure all support this from GitHub Actions) over static keys. Never run claude login during an image build — that embeds a credential in a Docker layer that may be cached or pushed to a registry.

Is Claude Code safe to run in CI without any sandboxing?

No. Without sandboxing, Claude Code runs with the full permissions of the CI runner process, access to all environment variables in the job, and unrestricted network access. A prompt injection attack via a malicious file or PR description could instruct the agent to exfiltrate secrets or modify files outside the intended scope. The risk scales with how sensitive your CI environment is — a job with access to production deploy keys or database credentials is a high-value target.

What permissions does Claude Code actually need inside a Docker container?

For most coding tasks: read-write access to the working directory, read access to relevant config files (package.json, tsconfig, etc.), and network access only if the task involves installing dependencies or calling an external API. Claude Code does not need root, does not need access to the Docker socket, and does not need the host network namespace. Start with the most restrictive configuration that allows the task to complete, and relax constraints only when you have a specific reason to.

How do I audit what Claude Code did during a CI run?

Enable verbose logging with --verbose and capture the full output to your CI log store. Claude Code emits a trace of tool calls — file reads, writes, shell commands executed — which gives you an action log you can review after the fact. For higher-assurance environments, wrap the agent invocation in a script that diffs the worktree before and after, and fails the job if changes fall outside an expected set of paths.

Does running Claude Code in a read-only container break it?

Only if you don't mount a writable workspace. The agent binary and its configuration can be on a read-only layer; what it needs writable access to is the working directory for the task. A common pattern is a read-only root filesystem with a single tmpfs or volume mount at /workspace where the agent reads and writes files. This satisfies the agent's operational requirements while preventing modifications to anything outside that path.

Top comments (0)