IBM (HashiCorp) Vault is built to manage secrets. AI coding agents are not. A Vault-backed MCP broker lets agents run authenticated commands without ever receiving credential values.
The best place for a secret is IBM (HashiCorp) Vault. The worst place is an AI agent's context window.
Vault, IBM (HashiCorp), was built for the job: identity-aware access, policy, dynamic credentials, audit trails, rotation, and revocation. An AI coding agent was built to reason over prompts, inspect files, call tools, and summarize results. Giving it an API key does not make it more useful for long. It makes it an accidental secret manager with a transcript, a tool log, local history, and potentially a path back to a model provider.
Your AI agent is not a secret manager. Vault is.
The model does not need the Jira token. The test process does. The agent should request a task, not receive a credential. Vault should store the secret, enforce the policy, issue short-lived access, and record the read. A local broker should resolve the value only for the process that needs it, then return scrubbed output to the agent.
This is why I built a Vault-backed local broker for VS Code and MCP. The developer signs in with IBM Verify(any oidc provider); the broker gets a short-lived, policy-scoped Vault token; Vault resolves the references; one child process gets the values; and the agent sees only redacted command output. Access is scoped twice: per user, because Vault only answers for the person signed in with IBM Verify, and per project, because the broker resolves only what that project declares.
The challenge is not vaulting a secret. Vault already does that exceptionally well. The challenge is closing the gap between Vault and the agent without turning the agent into another place secrets live and leak.
Vault can store the secret safely. It can also do something a .env file cannot do: issue an ephemeral credential, generated for one job and expired on its own when the job is done. That is where Vault shines.
The trouble is how easy the other path is. You paste the value into the prompt and say "add this to my .env." Or you skip the instruction and let the agent add it for you.
Either way the value is now in the conversation, which means it is part of what goes to a hosted model provider and what gets saved in the transcript. Then the .env gets committed with the next change. Two places for the leak.
Let's see some common reasons, and you will admit these are all true..dont lie ;)
.env, and .env is in .gitignore." Until the agent writes a .env.local, a test fixture or a config file that is not on the ignore list, or stages everything with git add -A. And the ignore file does nothing for the copy that is already in the prompt.A platform team can mandate Vault in policy, and an auditor can write "secrets are managed in Vault" in a control description, but neither makes Vault easier than pasting a value into a prompt. Frictionless path is what we need. This is what I built.
GitGuardian's 2026 State of Secrets Sprawl report counted 28.6 million new secrets in public GitHub commits in 2025, up 34%, the largest single-year jump they have recorded. Secrets tied to AI services rose 81%. Commits co-authored by Claude Code leaked secrets at about 3.2%, against a 1.5% baseline.
That last tile is the "I'll rotate it later" answer. The Verizon DBIR 2025 put credential abuse as the top initial access vector at 22%, with a median of 94 days to remediate a secret leaked to GitHub.
Paste a key into an agent session and you have appointed the agent your secret manager, whether you meant to or not. It is a bad one, for reasons most people miss even after they have looked at the numbers.
.env without asking. Knostic documented Claude Code loading project .env files into memory without saying so. You never pasted the key, and it can still end up in a model request.GITHUB_TOKEN, cloud keys, whatever your profile exports.In August 2025 the malicious Nx "s1ngularity" packages did not bring their own secret scanner. A postinstall script prompted the victim's own AI CLIs, with their permission checks switched off, to search the disk for .env files, SSH keys, wallets and tokens. Wiz counted more than 1,000 valid GitHub tokens in the haul. A month later the Shai-Hulud worm harvested developer credentials across 500+ npm packages, and CISA's advice was to rotate all of them. In March the LiteLLM PyPI compromise went straight for environment variables on the one box that holds every provider key. I wrote about that one in Forty Minutes on PyPI. In every case the key sat where the agent, or anything running as you, could read it, and that made it one instruction away from leaving.
The agent should be able to use a secret without ever being able to read one.
This is the responsibility model the rest of the post builds on.
| Component | Allowed responsibility | Must not do |
|---|---|---|
| IBM (HashiCorp) Vault | Store and protect secrets; scope every read to the signed-in user; issue dynamic credentials; log access; support rotation and revocation | Become a developer copy-and-paste source |
| AI agent | Request a task and interpret redacted results | Receive, store, display, transform, or persist secret values |
| Local broker | Authenticate the developer; obtain scoped Vault access; resolve only the references the current project declares; launch a constrained process; redact output | Become a general-purpose secret-returning MCP server |
| Child process | Use a value only for the requested task and lifetime | Persist, echo, or exfiltrate it |
| Identity Protection | Discover shadow agents, shared secrets, non-human identities, and Vault bypasses | Replace secret controls, task authorization, or workflow controls |
The goal is not "give the agent Vault access." It is "let the agent request a narrowly scoped execution that Vault authorizes and the broker performs." That distinction determines where the secret is allowed to exist.
Vault already solves the storage, policy, identity, audit, and lifecycle parts of secret management.
Most easy integrations break the separation. The Vault CLI prints a value into a terminal the agent can read. A typical Vault MCP server returns a value as a tool result. A generated .env file leaves the secret where the agent can load it. Shell injection gives it to every process the agent starts.
The agent now has a credential in its context, its transcript, its tools, or its inherited environment.
I wanted a different pattern: the agent requests a command; an identity-aware broker resolves only the required Vault references; a short-lived child process receives the values; and the agent gets only the exit code and scrubbed output. The result is a VS Code extension plus a small local MCP server, called Vault dev broker.
OIDC authorization code with PKCE against IBM Verify, as a public client. It opens the browser, so MFA and passkeys work the way they already do for that developer. Tokens go into VS Code SecretStorage, which is the OS keychain. There is no Vault username or token to hand out: the broker presents the Verify JWT to a standard jwt auth mount and gets back a 30-minute Vault token under a policy templated on my sub.
So how easy? literally in vscode Cmd+Shift+P, type "store", give the secret a name, type the value into a password box. It goes straight to your personal path in Vault and the plugin puts the matching reference line on your clipboard, ready to paste into .env.vault. The value never lands in the workspace, the chat or the transcript. Adding a secret costs about the same keystrokes as pasting it into the chat, which was the whole point.
So when the agent says it needs the Jira token, type use vault_run. What the project keeps is a .env.vault file. It contains references rather than values and can usually be committed, provided the Vault paths, environment names, and other reference metadata are acceptable to expose to repository readers:
Two boundaries decide what a vault_run can touch, and they are enforced in different places.
Per user, enforced by Vault. The broker logs in with the IBM Verify token of whoever is signed in, and Vault maps that token's sub to an identity. The policy is templated on it: that user can read and write under secret/dev/users/<their sub>/, read the team's shared path, and nothing else. My personal vault secret or value is invisible to anyone else, even with the same plugin, the same project and the same .env.vault. "Store a secret in Vault" always writes under the signed-in user's own path.
Per project, enforced by the broker. vault_check and vault_run resolve only the references in the open project's .env.vault, under the workspace root, and the child process receives only those values.
The user boundary is a Vault policy; the project boundary is broker behavior. Nothing in Vault today stops a second project's .env.vault from referencing any shared path that same user may read.
Vault is not the missing control. Vault is the control.
The missing piece is a developer workflow that lets an agent use Vault-backed access without ever receiving the underlying credential. One instruction in CLAUDE.md, AGENTS.md or Copilot's instructions file tells the agent how to behave:
The broker also runs outside VS Code as a plain stdio MCP server, so the same setup works in Claude Code, Cursor, Windsurf and IBM Bob, and because it discovers its endpoints from the issuer it works with any OIDC provider. I have proven it with Okta as well as IBM Verify.
The agent can do exactly four useful things:
vault_run takes a command line, nothing else.vault_check reports which entries in the current project's .env.vault resolve for the signed-in user, as JIRA_API_TOKEN, never with a value. vault_init creates a starter file.vault_signin and vault_signout start and end the developer's sign-in; the developer finishes it in the browser.[redacted].A session where we are adding some new build or functionality...it needs a key/value. The agent calls vault_check, sees WHATERVER_API_TOKEN, then calls vault_run with npx tsx scripts/build-new.ts. The broker reads the references as the user signed in, spawns the command with those values plus an allowlisted environment (PATH, HOME, locale and a few others), and returns the scrubbed output. Because the policy is templated on my sub, the Vault audit log names a person for that read rather than "the dev key."
The broker exposes intentionally limited tools. It can sign in, initialize references, check whether a reference resolves, and run a command. It cannot return a secret value.
.env, project files, shell startup files, or agent instruction files.The last line matters more than it looks. The only thing the plugin ever puts on the clipboard is a reference, the .env.vault line, never a value.
At enterprise scale, Vault becomes more than a secure place to store values. It becomes the policy, identity, audit, and credential-lifecycle control plane for developer tools, workloads, and agents.
The question is not whether an AI agent should manage secrets. It should not. The question is whether thousands of agentic AI users (think marketing/design, development, engineering, and even executive-level users) using their agents can request narrowly scoped, short-lived Vault access without having to recreate a credential-copying workflow at every editor and terminal. Vault Enterprise is the deployment.
If your platform team already operates Vault Enterprise or HCP Vault Dedicated, the broker needs no new infrastructure. It needs three things the Vault team already knows how to create: a jwt auth mount that trusts your identity provider's issuer (IBM Verify, or any OIDC provider such as Okta or Entra), a role bound to the broker's audience, and a policy templated on the user. The plugin has a namespace setting, so it lands in whichever namespace your team already uses; HCP Vault Dedicated's admin namespace works the same way. Every read then flows through the audit devices,
On the developer side it is one broker for every harness, so the same .env.vault, the same sign-in and the same Vault policy follow the developer from tool to tool:
| Harness | How it connects | Status |
|---|---|---|
| VS Code (and Insiders) | The extension registers the broker for Copilot Chat agent mode; sign in and store secrets from the Command Palette | Built; the primary client |
| Claude Code | Standalone broker as a stdio MCP server (claude mcp add or broker.js setup); the open project is the workspace | Proven |
| IBM Bob | broker.js setup writes the entry into Bob's MCP settings | Configured; set WORKSPACE_ROOT to the project |
| Cursor | Same mcpServers entry in .cursor/mcp.json | Configured; set WORKSPACE_ROOT, Cursor ignores cwd |
| Windsurf | Same stdio entry, written by broker.js setup | Configured |
For a platform team that already owns Vault, the whole rollout: configure auth once on the Vault side, hand developers the extension or the broker, and every harness they use asks Vault for the signed-in user instead of asking the developer for a key.
Every team wants its own secrets, policies and identity provider mount. Namespaces give each business unit or platform team an isolated tenant inside one control plane. The plugin already has a namespace setting, so the same .env.vault grammar and the same sign-in work whichever namespace a developer's secrets live in.
Namespaces are also where the project boundary moves out of the broker and into Vault. Give each project its own path and policy, a role per project or a namespace per team, and Vault itself refuses a read from a project that has no business with that secret. Then a secret is available only to the signed-in user, only for the project it was issued to, and both answers come from Vault's policy and audit log rather than from a convention on a laptop.
At that scale somebody will leak something, and the question becomes how long it works afterward. The GitGuardian figure says the honest answer for static keys is years. A vault+dyn:// reference instead asks for a database credential generated for this command, and the lease TTL is the backstop when revocation does not happen. The best secret to leak is one that already expired.
Then there is the evidence. Vault's audit devices record every read, by whom, from which auth mount, and ship it to your SIEM for real-time action; use IBM Antenna; use IBM Identity Protection. We can combine these for true ITDR and ISPM.
The keys already pasted need a different tool. Vault Radar scans Git, CI/CD, Jira, Confluence and Slack for them, blocks new ones at pre-commit, and imports what it finds into Vault for rotation. It has an IDE extension, and HashiCorp's docs call out AI-introduced hardcoded secrets by name.
And the agents themselves. Vault 2.0 adds workload identity, OIDC federation to AWS, Azure and GCP and SPIFFE JWT-SVIDs, so workloads and agents can stop carrying static cloud keys at all. That is the road the plugin's next step runs on: an actor token for the agent, a JWT-SVID issued by Vault, so the broker acts as a named agent on my behalf instead of as me.
That is the job of IBM Identity Protection, the product formerly named IBM Verify Identity Protection, built on AuthMind's technology. It is agentless. It builds an observed picture of what human and non-human identities actually do, from network flows and identity provider events, rather than from what the configuration says they should do. IBM positions it as ITDR plus ISPM: it surfaces shadow assets, unauthorized local accounts, missing MFA, and secrets scattered across managers that nobody consolidated.
Next to Vault and the broker, these are the questions I want it to answer, each one something the first two layers cannot know:
Observation is half of it. Using IBM Identity Protection is the way to find all agents and all agentic AI usage. IBM's September 2026 Agent Identity preview describes Agent Identity receiving risk signals from IBM Identity Protection via the Shared Signals Framework, with Vault issuing short-lived credentials just in time, so a shadow-agent finding becomes a revoked session rather than a ticket in a queue. That is the kill path from Shared Signals and the Kill Switch.
sk-, ghp_, AKIA and xoxb-. Rotate whatever you find, then delete the history.mcp.json. An MCP server that needs a token should get it from your identity provider or a vault at start-up, never from a committed file.CLAUDE.md or AGENTS.md, and the agents I use respect it.Cmd+V. If it loses, people will paste.AI agents did not create secret sprawl. They make it easier to be more productive...to be a bit lazier: paste the sensitive value, run the task, worry about it later.
The answer is not another policy telling developers to be careful. It is a workflow that separates responsibilities. The agent requests work. Vault owns the secret. A broker resolves it for one constrained execution. Identity protection finds the people, agents, and credentials still going around the system.
Your AI agent is not a secret manager. Do not make it one.
The Verify Vault plugin described here is a personal prototype for testing and demonstration. It is not an IBM product and is not supported by IBM.
The source code for the VS Code plugin and the Vault dev broker is on GitHub: github.com/iamidentity-ai/vscode-verify-vault.