← iamidentity.ai/blog
IAMIDENTITY.AI
Secrets Sprawl IBM (HashiCorp) Vault AI Coding Agents Non-Human Identity IBM Identity Protection MCP
Built on IBM (HashiCorp) Vault

Your AI Agent Is Not a Secret Manager

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.

Robert Graham 15 October 2026 ~13 min read
The VS Code Command Palette with the IBM Verify Vault Store a secret in Vault command selected and a masked secret flowing into an IBM Vault card, above a dark agent chat where a pasted API key is struck out and replaced by a vault_run call that prints the value as redacted, with an IBM Identity Protection summary alongside.

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.

This is it

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.

01Why agents keep getting keys

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 ;)

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.

28.6M
new secrets in public GitHub commits in 2025, up 34%
GitGuardian 2026
2x
leak rate in AI-assisted commits vs. the baseline
GitGuardian 2026
24,008
unique secrets found in MCP config files
GitGuardian 2026
64%
of valid secrets leaked in 2022 still worked in 2026
GitGuardian 2026

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.

02Why an agent is a terrible secret manager

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.

When the agent became the thief

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.

03Ultimately this is what we want: use not read

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.

ComponentAllowed responsibilityMust not do
IBM (HashiCorp) VaultStore and protect secrets; scope every read to the signed-in user; issue dynamic credentials; log access; support rotation and revocationBecome a developer copy-and-paste source
AI agentRequest a task and interpret redacted resultsReceive, store, display, transform, or persist secret values
Local brokerAuthenticate the developer; obtain scoped Vault access; resolve only the references the current project declares; launch a constrained process; redact outputBecome a general-purpose secret-returning MCP server
Child processUse a value only for the requested task and lifetimePersist, echo, or exfiltrate it
Identity ProtectionDiscover shadow agents, shared secrets, non-human identities, and Vault bypassesReplace 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.

04Vault manages secrets. The agent runs work.

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.

The VS Code command palette filtered on ibm, showing three commands: IBM Verify Vault: Sign in, IBM Verify Vault: Copy access token (dev aid), and IBM Verify Vault: Store a secret in Vault.
Three commands. Sign in, store a secret, and a dev aid. That is the whole surface a developer touches.

Sign in

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.

Store a secret in Vault

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:

ANTHROPIC_API_KEY=vault+kv2://secret/dev/shared/anthropic#api_key JIRA_EMAIL=vault+kv2://secret/dev/shared/jira#email JIRA_API_TOKEN=vault+kv2://secret/dev/users/<your-sub>/jira#api_token DB_CREDS=vault+dyn://database/creds/dev-readonly#password PORT=5177

Scoped to one user and one project

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. 

Developer signs in with IBM Verify PKCE, MFA, passkeys AI agent calls vault_run("npm test") sees exit code + [redacted] Vault dev broker 1. resolve .env.vault refs 2. spawn child, minimal env 3. revoke dynamic leases 4. redact every value IBM Vault jwt auth, 30 min token policy templated on sub every read in audit log Child process has the real values for this command only exits, values gone Verify JWT command only read as you output, scrubbed
The value travels Vault → broker → child process. The agent only ever holds the command and the scrubbed result.

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:

Secrets come from Vault through the vault-dev-broker MCP server. Never ask me for an API key, never write one into .env, a shell variable or code, and never read .env.vault for values. When a command needs a credential, run it with the vault_run tool; the values are injected for that command only.

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.

05What the agent can do

The agent can do exactly four useful things:

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

06What the agent must never do

The agent never receives a secret

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.

  • It never sends a credential to model context.
  • It never writes a value to .env, project files, shell startup files, or agent instruction files.
  • It never exposes a value in an MCP tool result.
  • It never passes the developer's full shell environment to the child process.
  • It never turns Vault into "copy secret to clipboard."

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. 

07Operating this pattern at enterprise scale

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. 

Already running Vault Enterprise? This drops in.

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, 

Developer laptop Browser VS Code Claude Code IBM Bob Cursor Windsurf AI agent inside the harness sees tools, never values MCP tools it gets: vault_check, vault_run, vault_init, vault_signin, vault_signout 4 asks vault_run 7 exit code + output, values [redacted] Vault dev broker local stdio MCP server same broker for every harness, each starts its own copy resolves only the refs this project's .env.vault declares reads them from Vault as the user, with the user's token spawns the child process, redacts values before replying declares refs 6 values output .env.vault in the project JIRA_TOKEN= vault+kv2://secret/dev/ shared/jira#api_token references only, no values Child process runs the command with the resolved values plus an allowlisted environment, no GITHUB_TOKEN etc. OS keychain tokens live in VS Code SecretStorage or the macOS keychain Per project: enforced by the broker (.env.vault) 1 Company identity provider IBM Verify: SSO, MFA, passkeys any OIDC IdP (Okta, Entra) works too sign in: OIDC authorization code + PKCE in the browser, company SSO with MFA 2 JWT with a custom audience for Vault IBM Vault Enterprise or HCP Vault Dedicated, platform team jwt auth mount trusts the IdP issuer: discovery, JWKS 30 min token, policy templated on sub 3 5 KV secrets, namespace per team reads only declared refs, as the user secret/dev/users/<sub>/* the user's own space, read/write secret/dev/shared/* read only. Nothing else is granted Per user: enforced by Vault policy on sub audit device: every read, attributed to the person, shipped to the SIEM dynamic secrets with TTL leases Sentinel policies Optional observation layer: IBM Identity Protection watches network flows and IdP events around Vault for paths like shadow agents and shared secrets
Enterprise setup: every harness runs the same Vault dev broker, the developer signs in through IBM Verify, the broker reads only the references the project declares, as that user, from IBM Vault Enterprise, and the agent only ever sees redacted output.

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:

HarnessHow it connectsStatus
VS Code (and Insiders)The extension registers the broker for Copilot Chat agent mode; sign in and store secrets from the Command PaletteBuilt; the primary client
Claude CodeStandalone broker as a stdio MCP server (claude mcp add or broker.js setup); the open project is the workspaceProven
IBM Bobbroker.js setup writes the entry into Bob's MCP settingsConfigured; set WORKSPACE_ROOT to the project
CursorSame mcpServers entry in .cursor/mcp.jsonConfigured; set WORKSPACE_ROOT, Cursor ignores cwd
WindsurfSame stdio entry, written by broker.js setupConfigured

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.

08Finding agents and secrets outside Vault

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.

09Whats next? What should you do?

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.

Sources

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.