Credentials and Secrets Never Enter the Sandbox
Between October 2025 and February 2026, one researcher leaked live credentials out of Claude Code Security Review, Gemini CLI Action, and GitHub Copilot Agent with nothing but PR titles and issue comments, disclosed in April 2026. All three agents held secrets in the same runtime that parsed attacker text. The Comment and Control incident is the cleanest proof that the only credential an agent cannot leak is the one that was never reachable from where its code runs. This is the credential half of the environment's perimeter.
Scoping a token is a bet; removing it is a control
In Anthropic's original coupled design, model-generated code ran in the same container as the credentials. As the Managed Agents team put it, "a prompt injection only had to convince Claude to read its own environment." And once an attacker holds those tokens, they can "spawn fresh, unrestricted sessions and delegate work to them." The intuitive fix, narrowly scoped tokens, gets a pointed dismissal: scoping "encodes an assumption about what Claude can't do with a limited token, and Claude is getting increasingly smart." The structural fix is that tokens are never reachable from the sandbox where the model's generated code executes.
The Nx s1ngularity compromise shows the stakes of getting this wrong on a laptop instead of in the cloud: a malicious postinstall script harvested ambient credentials from developer machines, yielding over a thousand valid GitHub tokens and 5,500+ repositories across 400+ users and organizations. Every shell inherited the human's full credential set, so one script took everything. See why the laptop model breaks for the general case.
Two patterns cover every credential
Anthropic's architecture uses exactly two mechanisms, and between them they cover both git and arbitrary tools:
| Pattern | How it works | What the agent sees |
|---|---|---|
| Bundle at init | The repo's access token clones the repo during sandbox initialization and is wired into the local git remote | git push and pull work; the token itself is never handled |
| Vault plus proxy | OAuth tokens sit in a secure vault; the agent calls MCP tools through a dedicated proxy that takes a per-session token and fetches the real credential server-side | Tool results only; never the credential |
The auth is consumed by infrastructure, not held by the agent. The capstone line from the article: "The harness is never made aware of any credentials." Not the sandbox, and not the brain either. This is the same boundary that makes egress control meaningful: a sandbox with no secrets and no open egress gives a hijacked model nothing to steal and nowhere to send it.
OpenAI converged on the bundle-at-init half independently. In Codex cloud environments, secrets "are only available to setup scripts. For security reasons, secrets are removed before the agent phase starts." Setup runs with internet access and credentials; the agent phase runs with neither by default.
Detection layers lost every time they were tested
The Comment and Control casebook entry is worth reading as a controlled experiment, because the vendors' runtime defenses were present and all of them failed. GitHub's environment filtering stripped secrets from the bash subprocess, so the payload read the parent processes' full environment from /proc with ps auxeww, recovering four credentials including a write-scoped GITHUB_TOKEN. Secret scanning matched ghs_/ghu_ patterns, so the payload base64-encoded the dump. The network firewall allowlisted github.com, so git push carried the loot out through the approved channel. Anthropic's mitigation blocked ps; cat /proc/*/environ achieves the same read. Anthropic rated the report Critical, CVSS 9.4, before re-classifying it to None in April 2026; no vendor assigned a CVE.
Prompt-layer, scanner-layer, and firewall-layer defenses were each bypassed; only removing the secret from the runtime wins. That is the verdict across the whole casebook of incidents.
Split trust: no single system reads a secret
Storage is the quieter half of the problem. The published record is nearly silent here: Codex documents "an additional layer of encryption" for stored secrets without naming the design, and the Anthropic article does not cover at-rest storage at all.
Split trust is envelope encryption with the roles divided: one system holds the ciphertext, and a separate system (a KMS-held key) is the only thing that can unwrap it, so neither system alone can read a customer secret. Plaintext exists transiently, in memory, at the moment of provisioning, and never lands in a reusable artifact.
The stronger form also binds the wrapped key to its owner: pass the tenant and resource identifiers as KMS encryption context, or AEAD associated data, at wrap time, and require the same context at unwrap. A wrapped key lifted from one tenant's row and presented under another's identifiers is then cryptographically inert, even to the system that holds the KEK. That closes failure modes split trust alone does not: a row-scoping bug, an IDOR, or a leaked row replayed against the unwrap path. Wallfacer (disclosure: the sponsor of this guide) ships this design; see the case study.
Snapshots freeze process memory, so a disk scrub is only the backstop
Cached environments are valuable, and they get shared: Codex caches container state for up to 12 hours, and for Business and Enterprise workspaces those "caches are shared across all users who have access to the environment." A git token, an ssh key, or a committer identity frozen into that image boots with every subsequent user.
The natural fix, delete the credential files right before capture, closes only half the leak. A VM or container snapshot freezes the live RAM of every running process, not just the disk, and the same holds for any checkpoint mechanism (Firecracker, CRIU, plain VM suspend). A token sitting in a long-lived service's environment is captured into the shared image regardless of which files the scrub removed, and every restored session inherits it in that process's memory. Keeping credentials out of the image takes two structurally different layers.
Structural exclusion. Per-identity credentials never enter a long-running process's environment in the first place. The process supervisor holds the token but withholds it from every service child it spawns; only the short-lived command that needs it (the clone, a private dependency fetch) receives it, in that command's own environment, and the command exits before capture. This layer does not depend on capture timing: no captured process holds the secret.
Disk scrub as backstop. Strip on-disk artifacts before capture, and abort the snapshot on a scrub failure rather than ship a tainted image. The scrub's load-bearing case is the credential with no env-only path: an SSH private key has to sit on disk for git over SSH to work, so a build that clones over SSH writes it and the scrub removes it.
Two more places a token hides, and a scrub list built from the obvious files misses both.
Keyring-resident tokens. Some CLIs, GitHub's gh among them, store tokens in the OS keyring (macOS Keychain, Linux Secret Service) and fall back to a plaintext file only when no keyring exists. A scrub that deletes files misses the keyring copy; the storage-agnostic clear is the tool's own logout command, run alongside the file removal.
The baked remote. Bundle-at-init wires the token into the local git remote, which is fine in a one-off sandbox that dies with its task and is exactly this leak in an image build. The form that survives sharing is a credential-helper script that holds no secret and reads the token from the invoking command's environment at call time. The same helper then serves a token-free image build and a token-bearing session boot.
Identity is then re-applied per boot from the initiating session, which is also what keeps versioned images shareable across a team in the first place. No published platform documents this as an enforced gate today. Codex's secrets-only-during-setup rule reduces the exposure window but does not verify the cached state is clean.