Keep provider keys out of the agent: one gateway, one token per task
If an agent can read your provider key, you cannot say who spent what. Put the key in one process, and give each task a token that names the task, carries its budget and dies with it. Then every cost has an owner and a stolen token is worth little.
π― For A developer who lets agents call paid model APIs
- Why a key in the agent's environment breaks attribution
- How a per-task token with a budget works
- What to store and what never to store
π The problem with a shared key
The easy setup puts the provider key in an environment file, and every script and agent reads it. It works, and it makes three things impossible. You cannot say which task made a call, because they all look the same to the provider. You cannot stop one task without stopping all of them. And any agent that can read its own environment can leak the key through a prompt.
Our own measurement in September 2026 found this still happening in one bridge runner that sourced the environment file directly. That finding is why the design below exists.
ποΈ The design
One small service holds the provider keys. It is the only code in the system that reads them, and a test scans the code to prove that no other module does. Agents never see a key. They call the service and present a token.
The token is issued for one task. It is tied to a fingerprint of the task packet, so it cannot be reused for a different job. It carries a budget and a per-call ceiling, an expiry time, and it is closed when the task ends. The service stores only a hash of the token, never the token. Each call is a row in the ledger with the task id, so spend has an owner.
The service also keeps its own books separate from other money paths. It does not import the trading code, and a test checks that.
π In numbers
Since 2026-09-21 the service has issued 1,415 task tokens. 1,367 are closed and 48 are not marked closed, some of them in flight or abandoned and waiting for expiry. There are 4 budget reservations. The test file for the module boundaries holds 17 tests.
π οΈ Practice: move the key out of the agent
- Find every place a provider key is read: environment files, config files, scripts. List them.
- Create a small service that holds the keys and exposes the same call interface your agents already use.
- Issue a token per task. Bind it to a hash of the task description or packet, a budget, a per-call maximum and an expiry.
- Store the token hash only. Show the token once to the caller.
- Log every call with the task id, model, tokens and cost, including retries and fallbacks.
- Add a test that scans your code and fails if any other module reads the key variable.
- Remove the key from every agent environment and from every shell profile that agents inherit.
β Check yourself
- Print the environment of an agent process. No provider key appears.
- Use a task token after the task is closed. The call is refused.
- Use a token with a different packet. It is refused.
- For any call in last week's ledger, name the task and its budget.
π§ When this does NOT work
- The gateway becomes the single point of failure. If it is down, no model call works. Run it as a managed service with a restart policy.
- Keys elsewhere. If a developer's shell profile still exports the key, the agent inherits it. Audit shells too.
- Tokens with long life. A token that lives a week is a key with extra steps. Tie it to the task.
- A single provider outage. The gateway does not remove it. Decide your fallback policy and log fallbacks.
- Local models. A model on your own hardware has no key. You still want the ledger.
π Evidence
| What we measured | Task tokens issued and closed, reservations, and tests for module boundaries |
| When | 3 November 2026, 21:53 UTC |
| Artifact | The task token and reservation tables of our transport database, the credentials module and its boundary tests in our private repository |
| Limit | The count shows use, not security. A review by someone outside the team has not been published |
β‘οΈ Next
See how budgets are reserved before a task runs in Costs, budgets and limits, and what to check in a connection in the MCP server security checklist.
Sources
- Costs, budgets and limits: reserving spend.
- MCP server security checklist: checks before connecting data.
- Permissions and data flow: what an agent may touch.
- Agent task receipts: what they prove: evidence per run.
π Article connections
Open the full knowledge graph βPublished article links. Select a node to open its article at the heading.
Article links Β· keyboard / text view
Same topic
- A vector base is a map, not a source: what we learned from retrieval
- When you cannot tell what a model call cost: freeze, then reconcile
- Splitting a big task for a cheap model: the 24,000-byte lesson
- Skills, MCP tools and rules: three ways to give an agent capabilities
- Eight shell and git mistakes our agents made, and the rule for each
- Several agents, one repository: ownership rules from real incidents
Next steps
Related reading
A vector base is a map, not a source: what we learned from retrieval
A vector base finds passages that are close in meaning to your question. It does not know which are true or current. Treat every hit as a pointer: open the file it names, check the hash, and take numbers from the artifact, never from the retrieved paragraph.
AI agents and MCP explainedWhen you cannot tell what a model call cost: freeze, then reconcile
Sometimes a model call times out and you do not know whether the provider charged you. Never record that as zero. Mark it uncertain, stop new paid calls, and let a named person reconcile it with the provider's statement. Refusals before generation are the exception.
AI agents and MCP explainedSplitting a big task for a cheap model: the 24,000-byte lesson
A cheap model does well on one small, well-defined job and badly on a big pile. We cap a task at 24,000 bytes and refuse larger ones before any model is called. Split by unit, one file or one country per task, and check the size before you start.
AI agents and MCP explainedSkills, MCP tools and rules: three ways to give an agent capabilities
Agents get abilities in different ways. A rule constrains what they do, a skill tells them how to do a job, and an MCP tool lets them call a function. Each has its own risk, so declare all three in a register and test that nothing exists unlisted.
π¬ Comments