Why does an agent never see its own credentials?
How covey brokers access to target systems at runtime: short-lived, scoped tokens that never sit in the sandbox as long-lived secrets.
Where does the password live that an agent uses to log into the ticket system? The obvious answer is an environment variable inside the container.
From there it turns up everywhere: in every crash dump, in every backup of the container, in every log line that catches it by accident.
That is the most uncomfortable question you can ask about any agent installation. The usual answer is exactly why a security team says no.
At covey, an agent has no password. It has an identity.
An identity, not a password
An agent presents its own identity on every request, not a shared secret. The control plane checks whether it is entitled to the target system and the requested scope, against the agent's ACCESS.md and the standing approval rules.
Only then does it exchange that identity for an access token: limited to one system, one scope, one short lifetime. A real RFC 8693 exchange against a third-party system needs an external OIDC provider configured. The built-in variant is the normal case — Keycloak and Vault are optional, not prerequisites — and it issues signed JWTs instead.
The limits themselves hold either way. That decision belongs to the control plane. Not the agent, not the daemon.
The secret behind it stays in one place
Somewhere the original access to a target system still has to be stored — a GitHub token, say, or an API key for Zammad. Covey keeps it encrypted in a Postgres column, with AES-GCM as the cipher and the COVEY_MASTER_KEY as the key.
The key itself lives only in the control plane's own environment, not in the database. Every stored value is bound to its organisation as well, so a ciphertext from one organisation decrypts to nothing in another.
A stored secret can be replaced from the interface. It can never be shown again. A value you could read out would end up in a chat message sooner or later.
A checkout shows how tight this is
One example makes it concrete. When an agent has to back up a bug report with a location in the code, it calls checkout.
It is not the runtime that downloads the repository archive — it is the daemon, over GET /repos/:owner/:repo/tarball/:ref, with the brokered token. The token stays in the daemon's memory. It never touches the sandbox's file system.
An ordinary git clone with a credential remote would write that same token straight into .git/config, permanently. That is exactly what covey avoids.
The daemon holds the token, the runtime never does
A slim daemon runs inside every sandbox, speaking one uniform protocol. It boots the actual runtime through a thin adapter — at covey, usually Claude Code.
inject_credentials is one of the messages on that protocol. It hands a short-lived, scoped token for one target system to the daemon.
That message reaches the daemon, not the runtime. The model reads the prompt and writes the text, and it never gets the token in its own context. It only ever sees the result.
The token does not vanish entirely, though — the daemon holds it, for the length of one call, in memory. So the precise claim is not that nothing in the sandbox ever touches a credential. It is that the credential never reaches the model's context, and never reaches disk.
What a lost sandbox loses
If a sandbox is lost or compromised, isolation and its short lifespan limit the damage. Critical state was never sitting in the sandbox to begin with.
A leaked token stays limited by its own scope and its short lifetime. And the container inherits nothing from its host's environment — it sees only what the control plane put there.
If the sandbox is lost, covey rebuilds it from configuration and the persistent home directory. No access token survives that. None was ever meant to.
Even the runner never sees the token
One layer further down sits the runner: the machine that actually starts the container. Through start_sandbox, it receives the agent's COVEY_DAEMON_TOKEN and an egress token to pass into the container.
That alone would let it impersonate any agent it hosts, in principle. What it does not get are the brokered target-system credentials themselves. Those go straight to the daemon, bypassing the runner.
So the boundary sits somewhere other than where you would first look for it. Not between the sandbox and the outside world. It sits inside the sandbox itself — between the daemon, which holds a token briefly, and the runtime, which never sees it at all.