← All posts Engineering

AI Coding Agent Secrets: Protect .env and Tokens

AI coding agent secrets should not rely on .env files, ignore rules, or tool permissions as the main boundary. The workable pattern is layered containment: keep real secrets out of the workspace, run agents in a constrained environment, disable broad network access, issue short-lived task credentials, redact logs, and scan every diff before code leaves the machine.

That matters because coding agents are useful for the same reason they are risky. They can read files, search code, run tests, inspect logs, call package managers, and use CLIs. If your local repo contains .env, cloud credentials, SSH keys, kubeconfigs, npm tokens, or CI tokens, you have to assume an agent with filesystem and shell access may reach them unless something stronger than a prompt-level rule prevents it.

This is not a claim that every agent always leaks secrets. The current controls differ across Codex, Claude Code, OpenCode, and similar tools. The safer conclusion is narrower and more useful: .env on disk is a poor security boundary once an autonomous tool can inspect files and run commands.

Start with the AI coding agent secrets threat model

For platform and security teams, the problem is bigger than accidental commits. There are at least five paths to control.

  • Passive context exposure: the agent reads a secret-bearing file and summarizes or stores it in model context.
  • Shell bypass: a read rule blocks the agent's file tool, but cat, sed, awk, rg, python -c, or node -e can still print the same file.
  • Prompt injection exfiltration: malicious project content or dependency output tells the agent to send secrets through curl, GitHub, package registries, webhooks, object storage, or issue comments.
  • Log and transcript leakage: test output, debug logs, shell history, PR descriptions, issue comments, support bundles, or compaction summaries capture secret values.
  • Persistence leakage: secrets land in generated .env.example files, snapshots, Docker layers, build artifacts, or commits.

Use this section as your first internal anchor: threat model, then map each risk to the controls in the rollout checklist.

What the main tool controls actually buy you

Codex local and CLI documentation describes an OS-enforced sandbox, approval policies, and network access off by default. In Auto mode, Codex can read, edit, and run commands inside the working directory automatically, while network commands and outside-workspace edits need approval. Codex cloud separates setup from the agent phase: environment variables can persist for the full task, while cloud secrets are available only to setup scripts and removed before the agent phase. OpenAI also explicitly lists code or secret exfiltration as a risk when internet access is enabled.

Claude Code has permission rules, /sandbox, and a sandboxed Bash tool with filesystem and network isolation. Its documentation is direct about an important default: sandbox read behavior can still allow reading the whole computer except denied directories. Credential paths such as ~/.aws/credentials and ~/.ssh/ need explicit blocking with controls such as sandbox.credentials or denyRead. Claude Code also supports a mask mode that replaces an environment variable with a session sentinel and injects the real credential through a proxy to approved hosts.

OpenCode permissions support allow, ask, and deny. Current documentation says .env reads are denied by default through patterns such as *.env and *.env.*, with .env.example allowed. That is useful, but it is still not the same as an operating system or container boundary. If shell commands can print files, read-tool denial alone is not enough.

The practical takeaway: vendor controls are necessary, but they are one layer, and their exact behavior needs version-specific verification. You still need filesystem isolation, egress control, short-lived credentials, and scanning.

Why .env is not a secrets boundary

.gitignore prevents accidental staging of untracked files. It does not stop an agent from reading those files. If a secret was already tracked, .gitignore does not remove it from Git history or the index. You still need to untrack it, rotate it, and scan for copies.

Agent-specific ignore files and deny rules reduce accidental reads, but they may not cover every path: shell commands, search tools, IDE-selected text, semantic indexing, subagents, MCP servers, logs, and generated files can all become alternate routes. Treat ignore rules as guardrails, not walls.

Environment variables have the same problem. They are convenient, but any process with access to the environment can print them with env, printenv, debug output, stack traces, or test failures. Docker guidance makes a related point for builds: build args and environment variables are inappropriate for build secrets because they can persist in images. Use secret mounts or runtime injection instead.

The safer architecture

The target is simple: the agent can run useful workflows without holding high-value credentials. When real access is unavoidable, make it narrow, short-lived, auditable, and hard to send elsewhere.

  • No real secrets in the repo tree. Commit only .env.example with dummy values. Store real local credentials outside the workspace.
  • Separate execution identity. Run agents under a separate OS user, container, or VM that cannot read your personal home directory, SSH keys, cloud config, browser tokens, or auth caches.
  • Workspace mount only. Give the agent read-write access to the repo, but do not mount secret directories by default.
  • Network deny by default. Allow exact package registries and test endpoints. Avoid broad wildcard domains. Treat github.com as sensitive if write-capable tokens exist.
  • Per-task credentials. Prefer workload identity, short-lived tokens, disposable tenants, read-only scopes, and explicit expiry.
  • Brokered injection. Use a broker, proxy, or sidecar that injects credentials only for approved hosts and methods, or exposes higher-level operations such as "run integration tests" without giving raw tokens to the agent process.
  • Agent-safe tests. Provide npm run test:agent, make test-agent, or similar wrappers that use fake credentials, local emulators, fixtures, mock JWT keys, and test tenants.

Rollout checklist for platform teams

Use this checklist as the baseline for a managed rollout.

  1. Repo templates: include .env.example only, with fake values and comments that tell developers where real secrets live.
  2. Managed agent config: centrally define deny rules for .env*, cloud credential paths, SSH directories, kubeconfigs, npm tokens, package publishing files, and auth caches.
  3. Command wrappers: publish approved commands such as test:agent that refuse to run when production credentials are present.
  4. Environment scrubber: strip high-risk variables before agent sessions, including cloud keys, CI tokens, deploy tokens, personal access tokens, and registry publish tokens.
  5. Egress policy: allow only required hosts and methods. Block generic paste sites, arbitrary webhooks, object storage uploads, and unknown domains.
  6. Broker logs: record task ID, repo, command, host, HTTP method, credential scope, and expiry for every injected credential.
  7. Pre-commit scanning: run tools such as gitleaks, git-secrets, or trufflehog before agent commits.
  8. Server-side protection: enable GitHub secret scanning and push protection. Treat these as compensating controls, not the primary defense.
  9. Diff review: require review of agent-generated changes to .env.example, Dockerfiles, CI config, auth code, scripts, and docs.
  10. Rotation playbook: define what happens when a token appears in a transcript, log, patch, image, issue, or PR comment.

Verify the version you actually run

Several community reports describe agents reading .env files despite deny rules or working around read restrictions through shell commands. Treat those reports as useful test cases, not timeless product facts. Tool behavior changes by version, surface, plugin, IDE integration, and configuration.

Before broad rollout, test your approved agent versions against the paths that matter: Read, search, Bash cat, rg, Python, Node, subagents, MCP tools, IDE selected text, logs, summaries, generated files, and network calls. Run the same tests for local CLI, IDE extension, cloud tasks, and CI-like agent jobs.

The operating rule is concrete: if an agent can do its work with fake or brokered credentials, do not give it real ones. If it must touch real access, make that access temporary, scoped, logged, and isolated from broad egress. That is the difference between using coding agents for useful engineering work and handing them the keys to your developer estate.

Get started

Deploy your fleet.

Put a fleet of sandboxed agents to work on your own infrastructure, provisioned in seconds and watched live from one console.

Get started

Admin-provisioned · Self-host in one command · Your data never leaves your VM