Where people sharing personal API keys with AI tools put them
They sit in three places: local AI client config files, Git repositories, and chat histories. Start with the config files, because nothing inventories them for you.
The usual path is ordinary. An engineer wants Claude or Cursor to read an internal system, installs a local MCP server, and pastes a key into that server's environment block. MCP (Model Context Protocol) is the standard way an AI assistant calls tools in other apps. Sharing personal API keys with AI tools spreads through exactly this shortcut, one laptop at a time, with no ticket and no record. Nobody is being reckless. There is no sanctioned path, so people build their own.
This post covers the Claude/ChatGPT/Cursor/Copilot ecosystem because that is where the documented vendor controls exist as of this writing. The same failure mode shows up with other providers' keys: Azure OpenAI keys pasted into local scripts, and AWS Bedrock credentials in .env files. Neither has a vendor-documented admin console either. The discovery method below, read the file rather than ask the vendor, applies to all of them.
No client vendor documents an admin console that lists the servers sitting in members' local config files (vendor docs read October 2026). Finding them means reading the files on each device, with a mobile device management or endpoint detection script. The paths, from each vendor's own documentation:
- Claude Desktop:
~/Library/Application Support/Claude/claude_desktop_config.jsonon macOS,%APPDATA%\Claude\claude_desktop_config.jsonon Windows, servers undermcpServers(modelcontextprotocol.io). - Claude Code:
~/.claude.jsonfor local and user scope,.mcp.jsonat the repo root for project scope. That file also holds the sign-in session, so read only itsmcpServersobjects (code.claude.com). - Cursor:
~/.cursor/mcp.jsonglobally,.cursor/mcp.jsonper project (cursor.com/docs/mcp). - VS Code with GitHub Copilot:
.vscode/mcp.jsonand a user-profilemcp.json, both now marked deprecated, plus.mcp.jsonat the project root and~/.copilot/mcp-config.json(code.visualstudio.com). - Devin Desktop, formerly Windsurf:
~/.config/devin/mcp_config.json, and the older~/.codeium/windsurf/mcp_config.json(docs.devin.ai). - Codex:
~/.codex/config.toml, one[mcp_servers.<name>]table per server (learn.chatgpt.com).
Run the same sweep across repositories and any chat export you can reach. A fuller version of the discovery pass is in the guide to finding installed MCP servers.
What do the key issuers already catch?
More than most security teams assume. Some of it is on by default and the rest is a license line, before you build anything.
GitHub secret scanning is free and automatic on public repositories. Private and internal repositories need GitHub Secret Protection, at $19 per active committer per month on GitHub Team or Enterprise. Push protection for users is on by default for public repositories on GitHub.com; repository push protection is off by default and needs Secret Protection (docs.github.com, GitHub Advanced Security, checked October 2026). OpenAI and Anthropic keys are partner patterns, so they carry push protection and validity checks (docs.github.com, checked October 2026).
OpenAI says sharing API keys is against its Terms of Use, and that it disables a key as soon as it is found on the public internet or inside an app-store app (help.openai.com, checked October 2026). Anthropic takes part in GitHub's partner program, deactivates exposed Claude API keys automatically and emails the owner; a personal key is archived when its owner is removed from the organization (support.claude.com, checked October 2026).
Turn these on first. They cost a license line and a configuration change, and they catch the loudest failure mode, which is a key committed to a repository. They do nothing about a valid token sitting quietly in a config file on one laptop, which never gets near git push.
What API Key Governance and inference hooks cover
Four vendor-side controls exist today, and they do not overlap. None of them, alone or together, covers a key already pasted into a local MCP server's config file.
| Control | What it gates | Maturity (per vendor docs, Oct 2026) | Where it lives | What it misses |
|---|---|---|---|---|
| GitHub Secret Protection | Commits before push | Generally available | $19 per active committer per month on GitHub Team or Enterprise | Keys never committed to a repo |
| OpenAI API Key Governance | Key creation (service-account-only, or block new keys) | Announced 15 September 2026 | OpenAI Platform settings | Keys already created before the policy was turned on; no rotation |
| Claude Enterprise Inference hooks | Prompt content, before inference | Beta | Claude Enterprise | Anything outside the prompt path: config files, repos |
| ChatGPT Enterprise network controls | Workspace membership at the network layer (ChatGPT-Allowed-Workspace-Id header) |
Not stated | Your network proxy or SASE, for ChatGPT Enterprise | Prompt content itself, with no documented inline filter |
OpenAI's API Key Governance, announced 15 September 2026, lets admins allow only service-account keys or block new key creation outright (developers.openai.com, checked October 2026). It narrows who can create a personal key going forward. It does not claim automatic rotation of keys that already exist, so do not plan on one.
For secrets typed into a prompt rather than a config file, Claude Enterprise has Inference hooks, in beta. Each governed prompt is sent to the organization's own security server for an allow or deny verdict before inference, with no redaction step: the verdict is binary, not a scrub (platform.claude.com, checked October 2026). ChatGPT Enterprise has no documented native equivalent for inline prompt filtering. Review runs after the fact through Compliance Platform partners, and a ChatGPT-Allowed-Workspace-Id header injected at the network keeps people off personal workspaces, but it does not inspect what's typed into a sanctioned one (help.openai.com, checked October 2026).
The asymmetry matters when you decide which assistant gets which data: one vendor documents a prompt-time content gate, the other documents workspace-level network controls plus after-the-fact review. Neither touches a project-scoped key already pasted into a local environment file. That gap is what the next section is about.
Remove the reason to paste a key
People paste keys because the sanctioned path does not exist yet. Build the path and the pasting drops, because the key stops being the only way in.
The rest of this section describes how Elaichi, specifically, implements that path. This is vendor self-report, not an independently audited claim: treat the architecture description as "how one product says it works," and verify against your own vendor's documentation before relying on it for a compliance control.
Elaichi is a governed MCP control plane. Every company SaaS account is connected once, and the tools those accounts expose are served through one organization-wide MCP endpoint at https://api.elaichi.ai/mcp. Claude, ChatGPT, Cursor, any MCP client, and the Elaichi Agent all point at that same address and sign in over OAuth (an authorization standard where the client receives a scoped token instead of a shared secret). Clients register themselves through dynamic client registration with PKCE (a challenge-response extension to OAuth that stops an intercepted authorization code from being replayed), so there is no client ID, secret, or header for a person to type or to leak.
Four properties do the work, as Elaichi documents them:
- No key to hand out. Connector credentials never live in Elaichi's application layer. A separate credential service holds per-account secrets, encrypted at rest with AES-256-GCM, and owns token refresh. A failed refresh marks the connection
needs_reauthrather than failing silently. - The model never handles the credential. The model finds a connected tool with
search_toolsand runs it withexecute_tool, two tools Elaichi exposes over MCP. The credential is read and the third-party call made server-side, in the organization's region. Tool results are scrubbed for secret-shaped values before they reach the model, as a backstop, not the primary control. - Nothing secret is readable back. Reading an account's configuration returns public values plus
secret_paths, the list of dot-paths that were encrypted, carrying none of the underlying values. Editing one is refused by the API. - Revocation is a database write, not a key rotation. The grant's
revoked_atfield is re-read from the organization store on every call, with no cache. In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change.
That last point is the one an offboarding checklist cares about. Disabling an identity provider account does nothing to a static key sitting in a config file on a laptop. The key keeps working until someone revokes it at the issuer, which can be days later or never. A grant to a governed endpoint dies on the next tool call, because the revocation check happens per-request rather than per-session. The argument for OAuth over static keys generally, not specific to this vendor, is set out in the comparison of the two credential shapes.
There is also no third-party server to vet in this model. Elaichi authors, maintains and serves its connectors from its own infrastructure, rather than listing servers other people run, so adopting the path does not mean approving somebody else's code onto a laptop. That is a real tradeoff against a registry-based approach, not a strictly better one: you gain a single vendor to audit and lose the option of a community-maintained connector for something niche. Where your connectors come from covers that distinction in more detail.
The path only removes the reason to paste a key if the app people want is actually on it. Elaichi's catalog holds 600+ connectors, and where a connector needs the organization's own OAuth app, an admin with connector:manage adds it. Check the connector catalog before you write the policy line below, so the policy isn't asking people to use something that doesn't exist yet. The cost side: building or buying this is more setup than flipping on GitHub push protection, and it is only worth it once more than one or two engineers are already pasting keys, which is the trigger condition in the last section of this post.
The one policy line worth writing
Write one sentence people can remember at the moment they are about to break it.
No personal API key goes into an AI client's config, a prompt, or a repository. If the app is on the company MCP endpoint, connect it there. If it is not, file a request and we will add it.
That line works because it names the alternative in the same breath as the prohibition. A rule with no sanctioned path is a rule people route around, and the routing is invisible, which is the whole shadow AI problem. Pair it with a request route. In Elaichi, any member can file an access request with no permission needed, and resolving one takes member:manage.
What to do when a key turns up
Revoke first, then rotate, then read the usage. In that order, because every minute between discovery and revocation is a minute the key still works.
- Revoke at the issuer. Not at the gateway, not in the config file. The key is valid until the system that issued it says otherwise.
- Rotate the replacement into a sanctioned place. A service account the platform team owns, or a connection on the governed endpoint. Never back into the same config file.
- Read the usage history at the issuer. You want the window between creation and revocation, and whether any call came from somewhere you do not recognize.
- Sweep for copies. The same key is often in a second config file, a
.env, and a chat message. Use the paths listed earlier in this post. - Record what you did. If the app also sits behind Elaichi, disconnecting that account takes effect on the caller's next request, not on a schedule. Elaichi writes one entry per tool-call attempt, succeeded or failed.
What a governed endpoint does not stop
It does not stop someone pasting a key into a chat window. An MCP endpoint sits between a client and a SaaS account. It never sees the prompt, so it cannot inspect one. This is a structural limit of the architecture, not a missing feature.
That half of the problem belongs to the issuer controls and to DLP (data loss prevention tooling that inspects content leaving the company). Four layers, each covering a different point in the path, none of them redundant with the others:
| Layer | Example control | Catches |
|---|---|---|
| Prompt content | Claude Enterprise Inference Hooks | A secret typed into a chat window, before inference |
| Commit content | GitHub push protection | A secret committed to a repository |
| Key issuance | OpenAI API Key Governance | A personal key being created in the first place |
| Tool call / credential | Governed MCP endpoint | A credential being read or misused during a tool call |
Treating any one of these as the whole program leaves the other three gaps open. How CASB and DLP see AI traffic covers what each layer observes in more detail, and why people paste company data in the first place covers the underlying behavior.
One more specific limit. The prompt-injection write gate in the Elaichi Agent does not apply to POST /mcp and structurally cannot, because an MCP server never sees a user prompt. It only sees a tool call with parameters. What does hold on the endpoint is permission checks per operation, the forbidden classification, output redaction, OAuth scope limits, and full audit logging.
And there is a case where none of this is yours yet. If nobody has wired an AI client to a company system, and the only keys in play are a handful of model API keys on a platform team's service accounts, the issuer controls plus a rotation habit are the whole program. Buying or building a governed endpoint before that point is solving a problem you don't have yet. The signs you do not need a gateway yet is the better read in that situation. Come back when the second engineer pastes a production key into a config file, because that is the week the shortcut becomes a pattern instead of an incident.
For the shape of the thing you would be adopting, start with the control plane explainer. For the laptop side of the cleanup, replacing personal MCP servers picks up where the discovery sweep ends.