
Google's new Credentials API for Gemini managed agents keeps secrets out of the sandbox. The agent gets a placeholder, and a proxy swaps in the real token on the way out, so the agent "cannot read back the tokens it is using."
The boundary is a domain. The docs say the proxy "authenticates every outbound request to that domain," with no per-path, per-method or per-action filter documented. Whatever the token is allowed to do on that host, the agent can do.
That moves the real control to the token's own scope and to the hooks you put in front of tool calls. Hiding the secret stops theft. It does not stop misuse.
What shipped
On 17 September Google swapped its managed agent from antigravity-preview-05-2026 to antigravity-preview-09-2026, the Antigravity coding agent's harness running on Gemini 3.8 Flash, available in AI Studio and the Interactions API. It came with two new pieces: a Files API for moving data in and out of the sandbox, and a Credentials API for letting the agent call the services you already use.
For the Credentials API, you POST /v1beta/credentials with one of three types. A bearer_token takes a token plus an optional header name and prefix. An oauth2 credential takes a client ID, secret, refresh token and token URL, and the proxy handles the refresh cycle, including swapping in a rotated refresh token when the provider issues one. An environment_variable credential is for client libraries that read secrets from the process environment.
Secrets are write-only. Every endpoint returns metadata, never the value. Rotation is a PATCH that "takes effect on the next proxy resolution," and deleting a credential makes every rule still pointing at it fail to resolve. That is a clean design, and a big improvement on the common pattern of pasting a personal access token into a system prompt or an env file the agent can cat.
How the token gets attached
You wire a credential to a destination in the environment's network allowlist:
"network": {
"allowlist": [
{ "domain": "api.github.com", "credential": "github-production" },
{ "domain": "github.com" }
]
}
From then on the proxy adds the header to every request the sandbox makes to api.github.com. Remote MCP servers take a credential field the same way. For environment variables, the sandbox sees a string like __GEMINI_CRED_slack-bot-token__, and the proxy replaces it with the actual secret only for requests to a domain listed in that credential's trusted_domains. A request anywhere else is rejected outright, and the placeholder is not sent either.
So the exfiltration story is solid. An agent that has been talked into posting its token to a pastebin has nothing to post. The string it holds is useless outside the proxy, and the proxy will not carry it to an unlisted host.
What the domain boundary does not cover
The proxy does not know what the request is for. It sees a destination, and if the destination matches, it signs.
Take the example above with a classic GitHub token that has repo scope. The agent cannot read that token. It can still list every private repository the token reaches, open and close issues, push to unprotected branches, and delete them. Every one of those calls goes to api.github.com, and every one gets the header.
The harness ships with google_search and url_context among its default tools, which means the agent reads text from the open web as part of normal work. A README, an issue body or a fetched page that carries an instruction is the ordinary way an agent gets steered. The Credentials API does not claim to address that, and the docs do not mention prompt injection at all. Fair enough, it is a secrets feature. But the practical effect is that a steered agent now acts with your token instead of stealing it.
There is a subtler version too. The allowlisted domain is usually also a place you can write. If the agent reads something private through the authenticated API, a public gist or an issue comment on a public repo is a request to the same host. The proxy has no reason to object.
None of this is a flaw in the proxy. It is the same trade every egress allowlist makes. It just means the question "can the agent see my token" now has a good answer, and the question "what can the agent do with it" has exactly the answer it had before.
Three gaps the docs leave open
The documentation is clear about what it covers, so the gaps are easy to list.
The allowlist is domain-level only. No path, method or per-repository filter is described. If you want the agent to read from GitHub but never DELETE, the proxy will not enforce that for you.
Credentials live at the project level. The docs describe no per-agent or per-environment scoping. Any agent configuration in the project that knows the ID can reference github-production.
No proxy logging is documented. There is no audit trail or usage metric described for credential-bearing requests. Your record of what the agent did lives on the destination side, in GitHub's or Slack's own audit log, if your plan has one.
One more worth flagging: trusted_domains is optional on environment_variable credentials. The docs themselves tell you to "set trusted_domains on every environment_variable credential," calling it "the control that scopes where the secret can be used." Treat that sentence as a requirement, and put it in a review checklist, because nothing will fail if you skip it.
Credit where due on the literal-value trap, which the docs call out plainly. A plain string in environment.env is injected as text and "readable by anything running in the sandbox, including the agent itself." Use literals for NODE_ENV, never for secrets.
What I would do before wiring this up
The Credentials API solves one real problem well. The rest is on you, and most of it is old advice that suddenly matters more.
Scope the token to the job. Use a fine-grained GitHub token limited to the one or two repositories the agent works in, with read-only contents unless the task needs writes. The proxy will faithfully apply whatever permissions you gave it, so give it less.
One credential per agent purpose. Because credentials are project-wide, name them after the job (gh-docs-bot-readonly), not the service. It keeps a new agent config from quietly borrowing a broader token that happens to exist.
Put a hook in front of writes. The harness supports hooks that intercept tool calls before they run. That, or a custom function tool that makes the API call itself, is where a method or path rule belongs: block DELETE, block pushes to anything but a feature branch, block calls to repositories outside a list.
Turn on the destination's audit log. Since the proxy side is silent in the docs, GitHub's and Slack's logs are your only record. Check that you can filter by the token before something goes wrong.
Hiding a credential from an agent is now easy on Gemini, and it is a real step up. What the agent is allowed to do with the credential was never a secrets problem, and it still lives in the token's scope and in your hooks.