Keys and AI agents
2026-09-18
Coding agents are no longer a demo — they read repositories, run terminal commands, call MCP tools, and sometimes paste configuration back into chat. Each of those steps is a new surface where an API key can appear in plaintext: a log line, a crash report, a shared screen recording, or a model context window that outlives the session. Treating agent access like human developer access (one big .env and hope for the best) scales poorly.
Why agents amplify secret risk
A human developer usually knows when they export an environment variable. Agents follow instructions literally. If a prompt says "print debug output," the model may echo environment variables. If a tool schema exposes a secret field, the agent may fill it from whatever is loaded in the shell. MCP servers can request capabilities broadly unless you gate them. The failure mode is not malice — it is automation without an explicit approval boundary between "the model wants a key" and "this process receives a key."
Tooling chains compound the problem. An IDE plugin might load dotenv for convenience, then hand the same workspace to a background agent. A test runner and a linter do not need your production inference key, but they often receive it anyway because the parent shell was sourced once at the start of the day. Each hop increases the chance that a secret appears in output captured by telemetry you did not intend to enable.
Local-first vaults exist to shrink that boundary. The encrypted vault file on disk holds ciphertext; unlocking happens through the OS keychain or a passphrase wrap. Secret values belong in child process memory only for the command you launched — for example via latchkey run -- node ./agent.js — rather than in a parent shell that every tool inherits.
Scoped access beats all-or-nothing env
Project allowlists (such as a .latchkey.toml file listing permitted secret names) reduce blast radius when an agent runs inside a repo. The agent still might mis-use a key it legitimately received, but it should not automatically inherit every key on your laptop. Pair scoping with habit: one repository, one subset of providers, rotate keys when the scope changes.
Think of scopes as documentation that the tooling can enforce. When you onboard a new agent workflow, decide which provider keys it truly needs — often one embedding key or one chat completion key, not every SaaS token you have ever saved. If the workflow changes, update the scope before you add more secrets to the same project tree.
For MCP integrations, an explicit approval mode — requiring you to opt in before a server can retrieve secrets — turns "always on" tool access into a conscious decision. That matches how you would treat sudo or production deploy keys: default deny, approve per workflow.
Audit metadata without leaking values
When something goes wrong, you need to know which secret name was touched and when, not a dump of the value in a log aggregator. Local audit entries that record names and actions (without values) support post-incident review without creating a second copy of the secret in plaintext storage. Hosted audit export may arrive later; today the discipline is local logs plus your provider's usage dashboards.
Practical habits
- Never paste live keys into chat, tickets, or prompt files — use placeholders and inject at runtime.
- Prefer
LATCHKEY_VALUE=… latchkey add NAMEover typing secrets on the command line where shell history might capture them. - Run agents through a wrapper that injects env vars instead of exporting them globally in your profile.
- Shorten idle unlock windows on shared machines so decrypted master keys do not linger.
- When a key might have entered model context, rotate it — see our post on rotating a leaked key.
Human approval still matters
Automation should not mean silent consent. When a server or script requests access to a secret name you have not used in that repo before, pause and ask whether the request matches your intent. Approval gates are annoying on purpose — they convert a class of "the model asked nicely" leaks into a visible decision you can log locally. Over time that habit matters more than any single feature flag.
What Latchkey is not
A local vault does not stop a compromised operating system, malware in your session, or a malicious npm dependency from reading process memory. It does not replace provider-side key restrictions, IP allowlists, or spend caps. It gives you a clearer choke point: ciphertext at rest, scoped injection, and optional approval before MCP retrieval — so agent automation inherits structure instead of a flat env file.
Questions or threat-model feedback: Yusuf@yusuf-choudhury.com.