Skip to content

Guide10 min read

Coding agents need broad access. Production should not be part of it.

A coding agent inherits every credential your shell can reach, so a session that starts with a failing test can end at the production database. Seven controls that keep production out of reach, why each matters, and the test that proves it.

IntertraceSecurity engineering

Field guides from Intertrace security engineering for the people who run AI programs.

October 12, 2026 · 10 min read

Coding AgentsSandboxingCI/CD SecuritySecretsLeast Privilege
Contents
  1. 011. Write down what the shell can reach, then take most of it away
  2. 022. Isolate filesystem and network together, or neither holds
  3. 033. Hand the agent capabilities, not keys
  4. 044. Tier each call by the target it points at, not the tool it uses
  5. 055. Give the agent its own identity, then make branch protection bind it
  6. 066. Build agent-written code where no secret can see it
  7. 077. Put deployment behind a reviewer the agent cannot be
  8. 08Where Intertrace sits in this list
  9. 09Back to the migration

The request was ordinary: fix the failing migration test. The engineer started a coding agent in their usual terminal and went to a meeting. The test database was down, so the agent looked for another one, found a DATABASE_URL in an untracked .env.production file left over from an incident last quarter, and ran the migration there to check it worked. It did. The migration also dropped a column the production application still read.

The scenario is illustrative, but every element is common, and none of it needed a malicious prompt. The agent pursued the goal with the access it had. The access was the problem. The usual answer is more permission prompts, and developers turn on allow-everything modes because the prompts interrupt them, which leaves the agent with the laptop's full authority. The better trade is the opposite one: give the agent a large room with no door to production, and stop asking about things that cannot matter. Here is the checklist, each item with the reason it is there and the test that shows it works.

1. Write down what the shell can reach, then take most of it away

A coding agent in a developer's terminal has the developer's ambient authority: every credential the process can read or the environment already holds. Developers accumulate a lot of it, usually for good reasons, and rarely think of it as a list. Write that list for a typical engineer's machine and one CI runner, and ask of each item whether a task like fix the failing test could ever need it.

Ambient authority on a typical developer machine, and where it should live instead
Credential or accessWhat it can reachDoes a coding task need it?Where it belongs
Cloud CLI profile with an admin roleEvery resource in the account, including productionAlmost neverShort-lived, read-only role assumed on demand, outside the agent's workspace
Cluster config with a production contextDeployments, secrets and pods in productionNoA separate profile the agent's environment does not mount
Git hosting token with admin scopeBranch protection settings, workflow files, secretsPush to a feature branch onlyA dedicated agent identity scoped to the repository and branch pattern
Untracked .env files for staging or productionLive databases and third-party APIsNoA secrets manager, injected only into the job that needs them
SSH agent socket and keysBastion hosts and serversNoNot forwarded into the agent's workspace
Container runtime socketRoot-equivalent control of the hostSometimes, for buildsA rootless or remote builder, never the host socket

Why: most teams find the agent needs perhaps two items on that list, and those only in narrowed form. Everything else is blast radius, authority the agent can use by mistake or that an instruction hidden in an issue, a dependency or a web page can steer it to use. Test: run the list again after the changes and confirm each removed item is absent from the agent's environment.

2. Isolate filesystem and network together, or neither holds

Why: Anthropic's write-up on sandboxing its coding agent makes the key point: effective sandboxing requires both [1]. Without network isolation, a compromised agent can send out sensitive files such as SSH keys; without filesystem isolation, it can escape the sandbox and reach the network anyway [1]. Its implementation uses operating-system primitives, bubblewrap on Linux and Seatbelt on macOS, and routes network access through a proxy that limits which domains a process can reach [1]. Anthropic also reports that in internal use, sandboxing reduced permission prompts by 84% [1]. Isolation is what lets you stop interrupting the developer.

Check what actually counts as a boundary.

  • A git worktree or fresh checkout organizes the agent's edits, but it is not a security boundary; the process can still read your home directory.
  • A container is a boundary only if it does not mount the host's container socket, your home directory or your cloud credentials. Mounting the home directory for convenience brings every credential file along.
  • Egress should default to the package registries, documentation sites and APIs the task needs, through a proxy that logs every destination.
  • Local services count. A database tunnel or port-forward open on the host is reachable from a workspace that shares the host's network.

Test: have the agent request an unknown domain with curl. Expected: blocked at the egress proxy and logged.

3. Hand the agent capabilities, not keys

Why: anything the agent can read, the model can see, and anything the model can see can end up in a commit, a log, a pull request description or an outbound request. Keep secrets out of the workspace and give narrow capabilities instead: a proxy that attaches a token for git pushes to one repository, a test database seeded with synthetic data, an API sandbox key that cannot move real money. Anthropic's hosted version follows this pattern: git credentials and signing keys never enter the sandbox, and a proxy outside it attaches authentication only after checking the request [1].

Treat credential paths as protected. A read of a cloud credentials file, a kubeconfig, an SSH key or a .env file outside the project should ask a person, not because the agent is malicious but because no legitimate coding task needs it silently. The same applies to writes to the agent's own configuration, CI workflow definitions and dependency manifests, which change what the agent or the pipeline may do and deserve the review you give infrastructure.

Test: ask the agent to print the contents of the cloud credentials file. Expected: the file is absent from the workspace, or the read asks.

4. Tier each call by the target it points at, not the tool it uses

Why: the same command can be routine or catastrophic. psql against a local test database is development work; psql against the production host is a production change. terraform plan in a scratch account is harmless; terraform apply in the production account is an administrative change. Name two environments and decide by target: in development, code runs and local deletes do not wait for a person; once a call points at production, by hostname, account ID, cluster context or branch, consequential actions ask or are blocked.

Two environments, one reviewed doorFig. 1
Development tierRUNS FREELYCoding agentisolated workspace · own identityEdit checkoutRun testssynthetic dataInstall packagesvia mirrorPush branchfeature/* onlyNO PRODUCTION CREDENTIALS MOUNTEDEGRESS THROUGH A LOGGED PROXYReviewed mergesomeone else approvesDeploy jobenvironment reviewerProduction tierProduction DBRelease branchprotectedCloud accountLive serviceAMBIENT CREDENTIALSthe agent does its work on the left · the only way across is a merge someone else approved and a deploy someone reviewed

Inside the development tier the agent edits, tests, installs and pushes feature branches without asking. The only route into production is a reviewed merge and a deployment job with its own approval; the direct path through ambient credentials is the one to remove.

The classification has to come from the call itself, not from what the agent or the session claims. A session labeled development that runs a migration with a production connection string is a production call. Raise the tier when any argument points at production; never lower it because a header or configuration value says the work is only a test. Define those production targets (hosts, accounts, cluster contexts, protected branches) in policy.

Test: ask the agent to run the migration against the production database URL. Expected: no route to the host, or an approval that names the host.

5. Give the agent its own identity, then make branch protection bind it

Why: branch protection only works if the agent is subject to it. GitHub blocks force pushes on protected branches by default and can require that the most recent push be approved by someone other than the person who pushed it [5]. But by default its restrictions do not apply to repository administrators; applying them requires the setting that disallows bypassing [5]. An agent running on an engineer's admin token pushes straight past rules the team believes are in force.

There is a subtler problem. When the agent pushes as you, its commits are your commits, so your approval of its pull request is a self-review. Give it a separate identity, a bot account or an app installation scoped to the repositories it works in, allowed to push feature branches and open pull requests and nothing more. Then the rule requiring approval from someone other than the pusher means a person reviewed the agent's work.

Test: ask the agent to force-push to the default branch. Expected: held for approval or blocked at the gateway, depending on the role, and refused by branch protection, independently.

6. Build agent-written code where no secret can see it

Why: every pull request an agent opens is code CI will run. OWASP's CI/CD risk list calls the general problem poisoned pipeline execution: anyone who can change source can change what the build does, directly by editing pipeline configuration or indirectly through files the pipeline uses, such as build scripts, test code and linter configuration [2]. An agent fixing a failing test edits test code by definition. If that test runs in a job that can see deployment secrets, the agent's change, or an instruction smuggled into it, runs with those secrets.

GitHub Security Lab's guidance on pwn requests describes the sharpest version. Workflows triggered by pull_request_target run with write permission to the target repository and access to its secrets, so combining that trigger with an explicit checkout of the pull request's code can lead to repository compromise [3]. The recommended split: an unprivileged pull_request workflow builds and tests the untrusted code and saves results as artifacts, and a separate privileged workflow triggered by workflow_run uses those results, treating the artifacts as untrusted too [3]. OWASP's recommendations match: run pipelines over unreviewed code on isolated nodes without secrets, and give each pipeline only the credentials it needs [2].

Keep agent-written code away from CI secretsFig. 2
Agent's pull requestuntrusted codeUnprivileged buildpull_request · no secretsResults as dataartifacts, untrustedPrivileged stepworkflow_run · commentsPULL_REQUEST_TARGET+ PR CHECKOUTSecrets + write tokenpwn requestLATER, AFTER HUMAN REVIEWProtected mergeapproved by someone elseDeploy environmentsecrets after reviewProductionrelease onlyagent-written code builds without secrets · secrets appear only after a person approves the deploymentAMBER = TREAT AS UNTRUSTED INPUT TO THE NEXT STEP

The agent's pull request builds in an unprivileged job, and only its results, treated as data, reach a privileged step. Deployment happens later, from the protected branch, behind an environment reviewer. The dangerous shortcut is a privileged trigger that checks out the pull request's code.

Agents that run inside CI, triggered by an issue or a review comment, need the same treatment from the other side. Their input is whatever a contributor wrote, so their job token should be read-only by default, with any write step split into a separate, reviewed job.

Test: have the agent edit a test file to print environment variables, open a pull request, and check the CI log. Expected: no secrets in that job.

7. Put deployment behind a reviewer the agent cannot be

Why: GitHub environments can require named reviewers, prevent people from approving runs they triggered, restrict which branches may deploy, and release environment secrets to a job only after those rules pass [4]. With the agent on its own identity, self-review prevention means it cannot approve its own deployment even if its token could reach the approval API.

Test: have the agent's identity approve its own deployment. Expected: refused by the environment's self-review rule.

Where Intertrace sits in this list

Intertrace's gateway reads what each tool call does from its name and arguments: git force-pushes, branch deletes and protected-branch pushes, SQL statement shape, shell splitting and substitutions such as curl piped to sh and sudo, cloud operations, and reads or writes of credential and CI paths. That classification only raises a call's consequence tier, and the agent's role decides what runs, what asks once a call points at production, and what is blocked. Read-only GitHub scans find committed keys, MCP configurations and AI usage in code and CI without storing key values. The sandbox, agent identity and CI split stay with your platform team.

Back to the migration

Replay the opening against the checklist. In an isolated workspace, the untracked .env.production is not mounted, so the agent never sees the production URL. If it somehow had one, egress limited to the test database and package registry refuses the connection. If both failed, tiering by target classifies a migration against the production host as an irreversible production change and asks the engineer, who sees the hostname on the approval screen. Any one of the three breaks the chain, and none of them makes the agent ask before running the test suite. One gap the checklist does not close on its own: a nested agent or script launched from the session runs outside the governed path, so check what the agent can start, not only what it can call.

Sources

Reporting, research and specifications this piece draws on. Links go to third-party sources; analysis and recommendations are Intertrace’s own.

  1. 01Beyond permission prompts: making Claude Code more secure and autonomous · Anthropic
  2. 02CICD-SEC-4: Poisoned Pipeline Execution (PPE) · OWASP Top 10 CI/CD Security Risks
  3. 03Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests · GitHub Security Lab
  4. 04Managing environments for deployment · GitHub Docs
  5. 05About protected branches · GitHub Docs

About this desk

Intertrace

Security engineering

Field guides from Intertrace security engineering for the people who run AI programs.

All 22 pieces by Intertrace

Dated October 12, 2026 · added to intertrace.ai October 17, 2026

+ Runtime enforcement

See these controls on your own agent traffic.

Intertrace sits inline between your agents and the models, tools and MCP servers they call, and decides every call before it runs.

Keep reading

All insights →