Isolating agent sessions from production credentials

A coding agent is not a tool you invoke and forget; it is a session. It reads files, runs commands, keeps state between steps, and accumulates context over minutes or hours. The session you hand it is usually your own — same shell, same environment variables, same credential stores, same cloud CLIs already logged in. The agent inherits everything your terminal can reach, and unlike a human operator, it will not pause to ask whether it should use it.

Why production credentials end up in agent sessions

Credential leakage into agent sessions is rarely a single dramatic mistake; it is a pile of ordinary ones:

  • The shell environment carries AWS_*, DATABASE_URL, and GITHUB_TOKEN because they were exported for other tools.
  • Config files sit in the working tree or home directory: .env, .npmrc, ~/.docker/config.json, kubeconfig with embedded certificates.
  • Cloud CLIs are already authenticated, so any command the agent runs acts with your identity.

An agent that can read files and run commands in this environment does not need to be clever to obtain production credentials. It just needs to look.

Isolate the session, not just the sandbox

Sandboxing restricts what the agent can do; session isolation restricts what it can see. The first layer is environmental: run agent sessions under a dedicated user, in a container or VM, or at minimum in a shell with the environment stripped to a known allowlist. Remove interactive logins and logged-in CLIs from the session’s reach. The session then starts with an empty surface: no ambient credentials to inherit.

This is the layer most teams skip because it costs convenience. But it is also the layer that makes everything downstream simpler, because the question stops being “what did the agent see?” and becomes “what did we explicitly give it?”

Cross the boundary at spawn time

An isolated session still needs credentials to do useful work. The design question is how they cross the boundary. Sending values through the prompt puts them into the model’s context and the session transcript — permanent residue. Writing them to files the agent can read defeats the isolation. The workable pattern is injection at process spawn: a broker resolves the named credential and places it into the subprocess environment as the command starts. The agent never reads the value; the tool inherits it as an environment variable that lives only for the duration of the process.

The return path matters as much as the injection path. Tools that echo their environment, print connection strings, or dump configuration can push the value back into agent-visible output, where it lands in the context window. Sanitizing stdout and stderr — including base64 and URL-encoded variants — closes that loop.

Session persistence is a leak channel

Isolated sessions still persist. Checkpoints, transcripts, and logs capture what the model saw; shell history and coredumps capture what the process had. If a credential value ever entered the session, it can survive in artifacts long after the session ends. Treat anything the session writes as potentially sensitive, and keep values out of the session rather than relying on scrubbing after the fact.

What a broker changes

A credential broker formalizes the boundary: the session gets access by name, values are resolved at the moment they are needed, and every resolution is recorded. trustless does this with subprocess environment injection, output sanitization, and an append-only audit log; the command reference is in the docs. The isolation work is yours — the boundary is the product.

If you killed every ambient credential in your shell and started an agent session from scratch, what would it still be able to reach?