Credential-Scoped Agent
An agent that calls an authenticated API with a token it can never read — injected at the egress layer.
An agent that does real work against an authenticated API — GitHub, here — using a token it can
never read. The token is registered as a credential, not an environment variable: it's
injected into matching outbound requests at the egress layer, so the agent can call
api.github.com as you while the value itself never enters the container's filesystem or
environment. Revoking it takes effect immediately, mid-session, without touching the running
sandbox.
Setup
Start OpenSandbox in Docker (one-time setup):
bunx alineo-cli initExport the agent's model key and a GitHub token:
export NVIDIA_API_KEY=... # https://build.nvidia.com — free tier
export GH_TOKEN=... # a GitHub PAT (classic or fine-grained); read-only scopes are enoughGH_TOKEN is just the raw token — the agent spec (agents/github-agent.json) wraps it as
Bearer ${GH_TOKEN} so the injected Authorization header is well-formed for GitHub.
Credential injection rides on the same egress layer as network policy, so the server needs
egress.image configured and egress.mode = "dns+nft" — the default for alineo init since
this feature landed. On an older local config, add this to ~/.config/alineo/server.toml and
restart the server:
[egress]
image = "opensandbox/egress:v1.1.7"
mode = "dns+nft"Run it
What it does
Alineo.load() reads agents/github-agent.json, whose env.GITHUB_TOKEN is a
{ credential, host, injection } binding rather than a string. Because at least one binding is
present, load() creates the sandbox with credentialProxy: true and registers the token with
the egress sidecar's Credential Vault — it never becomes a container env var.
env.NVIDIA_API_KEY, an ordinary string, is exported the normal way.
The agent does authenticated GitHub work — told to curl https://api.github.com/user and
report the login, it does — with no token and no Authorization header of its own, and the call
comes back authenticated as you. The recipe echoes the agent's bash command and its output, so
you see the real request and the real response.
Audit — env | grep inside the sandbox turns up nothing, and a bare
curl https://api.github.com/user with no Authorization header of its own still returns
HTTP 200: the credential reached the request at the sidecar, not through anything the agent
could see.
Revoke — agent.sandbox.credentials.remove("GITHUB_TOKEN"), and the same bare request now
returns HTTP 401. The agent's own next call to api.github.com would fail the same way.
The point
AgentSpec.env is the obvious place to hand an agent a secret, but a plain env var is readable by
anything running in the sandbox — including code the agent wrote itself, and including a
prompt-injected instruction to print it. A credential binding gives the agent the capability
(authenticated calls to one host) without the secret, and leaves you holding the leash: one
remove() call cuts access at the network layer, with no redeploy and nothing to clean up inside
the container.