Credential-Scoped Agent

An agent that calls an authenticated API with a token it can never read — injected at the egress layer.

Advanced~10 mincredentialProxyCredential Vaultegress injection

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 init

Export 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 enough

GH_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

cookbooks/credential-scoped-agent
$bun install
$bun start
Simulated preview — no sandbox is actually created here.Run it for real →

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.

Auditenv | 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.

Revokeagent.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.