Where API keys leak with AI coding agents: the files, the tests and the caps that limit the bill GitGuardian counted 24,008 unique secrets in MCP configuration files on public GitHub in 2025, the largest evidence base for API key leaks in AI coding agent stacks, according to a report on leak paths published alongside LiteLLM's post-mortem of an October 2026 incident. LiteLLM's post-mortem traced the chain to a developer who committed an admin key for an internal LiteLLM Agent Platform deployment in `harnesses/opencode/opencode.json` on 27 May 2026; the file was deleted about three hours later but the key was never revoked, an attacker used it on 10 October, and a malicious `litellm==1.107.0` reached PyPI on 21 October. Railway separately disclosed that between 20 October 13:58 UTC and 22 October 03:32 UTC an attacker decrypted a subset of customers' environment variables using credentials taken from Railway's CI, seeking AI provider keys "to perform distillation attacks," with exposure capped at no more than 1.85% of workspaces. Where API keys leak with AI coding agents: the files, the tests and the caps that limit the bill The confirmed API key leaks that hit AI coding agent users in October 2026 did not run through a .env file. The most likely cause is a key typed inline into an agent config file that sits in the project folder and gets committed: GitGuardian counted 24,008 unique secrets in MCP configuration files https://www.gitguardian.com/state-of-secrets-sprawl-report-2026 on public GitHub in 2025. Next come keys stored by a hosted service that was breached, as at Railway https://stackness.dev/tools/railway on 20 to 22 October, and keys a build baked into a front-end bundle. Gitignoring .env stops none of the three. A hard spend cap on every key is what limits the bill. Where do API keys leak with AI coding agents? API keys leak from an AI coding agent stack through six paths, and the symptom is the same for all of them: a provider bill or usage graph that jumps overnight, or a revocation email from Anthropic, OpenAI or GitHub. The cause decides the fix, so the paths below are ranked by how much public evidence there is for each, with a test and a fix for each one. The most shared case shows how hard the cause is to pin down. A developer posted a Google Cloud cost anomaly https://x.com/JustLingonberry/status/2108982107846619209 of about $88,982 on 10 October, then wrote that another model had told him OpenAI Codex https://stackness.dev/tools/codex-cli published his .env to Cloudflare Pages https://stackness.dev/tools/cloudflare-pages ; that diagnosis is unverified. A Reddit post https://www.reddit.com/r/devops/comments/1xhoqdk/the 87k api key leak had nothing to do with env/ of 28 October built on an $87,000 bill gives no source I could find for it. The key sits inline in an agent config file you committed An inline key in a committable agent config is the leak path with the most evidence. Every agent reads a project-level config that is meant to be shared: opencode.json for OpenCode https://stackness.dev/tools/opencode , .mcp.json and .claude/settings.json for Claude Code https://stackness.dev/tools/claude-code , .cursor/mcp.json for Cursor https://stackness.dev/tools/cursor , .codex/config.toml for Codex, .gemini/settings.json for Gemini CLI https://stackness.dev/tools/gemini-cli . An MCP server's key pasted into one of them goes to GitHub with the next commit. LiteLLM's post-mortem https://docs.litellm.ai/blog/security-incident-oct-21-2026-attack-chain shows the whole chain. On 27 May 2026 a developer committed harnesses/opencode/opencode.json , holding an admin key for an internal deployment of LiteLLM Agent Platform, an experimental LiteLLM https://stackness.dev/tools/litellm service, to a public repository. A follow-up commit deleted the file about three hours later, but the key was never revoked and the original commit stayed in history. On 10 October an attacker used it, and on 21 October a malicious litellm==1.107.0 reached PyPI. Test: list the agent configs git tracks, then scan the whole history. git ls-files | grep -E ' ^|/ opencode\.jsonc?|\.mcp\.json|mcp\.json|settings \.local ?\.json|config\.toml|auth\.json $' gitleaks git -v --redact --log-opts="--all" . Fix: reference the key instead of pasting it: {env:VAR} or {file:path} in OpenCode, ${VAR} in .mcp.json , ${env:NAME} in Cursor's mcp.json , bearer token env var for an HTTP MCP server in Codex, and apiKeyHelper for Claude Code's own Anthropic key. Revoke any key that was ever committed; deleting the file does not remove it from history. A hosted service that stores your key was breached A breached platform leaks keys you never pushed anywhere. Railway disclosed https://blog.railway.com/p/preliminary-report-october-security-incident that between 20 October 13:58 UTC and 22 October 03:32 UTC an attacker decrypted a subset of customers' environment variables using credentials taken from Railway's CI, looking for AI provider keys "to perform distillation attacks". Railway put the exposure at no more than 1.85% of workspaces and told everyone who signed up before 21 October to rotate. Four days earlier, on the night of 16 October, an intruder reached OpenCode Console, OpenCode's hosted service; OpenCode reported the next day https://x.com/opencode/status/2111519637049319818 that the breach affected 1.4% of Console users, all with external provider keys linked. Users reported charges in the hundreds of dollars, a few above $1,000, according to TechCrunch https://techcrunch.com/2026/10/19/hackers-hit-ai-coding-tool-opencode-running-up-charges-on-users-ai-accounts/ , and one put his losses at $1,700, according to The Hacker News https://thehackernews.com/2026/10/opencode-console-breach-may-have.html . The OpenCode command line keeps keys on your machine and was not affected. Deleting a key from Console did not revoke it at the provider. Test: list every dashboard holding a provider key: hosting variables, an agent's cloud console, an LLM gateway. Fix: revoke at the provider, never only in the tool. Give each tool its own key with its own cap, so one breach drains one budget. The build baked the key into your front-end bundle A front-end build copies any variable with a public prefix into the JavaScript every visitor downloads. Vite https://stackness.dev/tools/vite 's docs say VITE variables end up in client code and should not hold secrets; Next.js https://stackness.dev/tools/next-js inlines NEXT PUBLIC values at build time. A coding agent asked to make an API call from a browser app reaches for those prefixes because they work. Sandeep Roy scanned 978 public apps https://dev.to/sandeep roy c4e518c3f2641/i-scanned-978-vibe-coded-apps-1-in-26-ships-a-secret-api-key-to-every-visitor-2nj1 built with Lovable https://stackness.dev/tools/lovable , Bolt https://stackness.dev/tools/bolt and v0 https://stackness.dev/tools/v0 and found a secret in 37 of them, nine of them AI provider keys. He found it first in his own app, after a repository scanner had passed it clean: the key lived in the hosting dashboard and entered the code only at build time. He built the scanner he used, a free open source tool called LeakLock, and I found no one who repeated the count. Test: search the build output, not the repository. grep -rEoh 'sk- proj|svcacct|ant-api03|or-v1 - A-Za-z0-9 - {8}|AIza 0-9A-Za-z - {35}' dist build .next/static out 2 /dev/null | sort -u Fix: move the call to a server route or an edge function, rotate the key first, and switch off public source maps. Agent state files ship inside a package Agent state files ship inside packages because nothing excludes them by default. When you choose "Yes, and don't ask again" on a Claude Code permission prompt, the command you approved, or a prefix of it, is saved to .claude/settings.local.json , inline Authorization header or API KEY= prefix included. Lakera watched the npm feed https://web.archive.org/web/20260516182335/https://www.lakera.ai/blog/your-ai-coding-assistant-just-shipped-your-api-keys and reported in April 2026 that of about 46,500 packages, 428 contained that file and 33 files in 30 packages held credentials. Lakera belongs to Check Point, which sells security tools. Claude Code now adds the file to your global git excludes when it first writes one, which keeps it out of commits. npm does not read git's excludes: in my test with npm 11.5.2, npm pack --dry-run still listed the file while git ignored it. Test: see what npm pack would publish. npm pack --dry-run 2 &1 | grep -E '\.claude/|\.cursor/|\.codex/|\.opencode/' Fix: a files allowlist in package.json , and never approve a command with a key written into it. The agent read a secret and kept it in its transcript A coding agent runs as your user, so it can open .env , ~/.aws/credentials or another tool's auth file unless a rule stops it. In one developer's 202 test runs https://dev.to/maria bcn/do-ai-coding-agents-leak-your-api-keys-3mfm , Claude Code and Codex with no rules opened .env in every task, and keys printed by program output ended up in session logs. Claude Code keeps transcripts in plain text https://code.claude.com/docs/en/claude-directory under ~/.claude/projects/ for 30 days by default. The other leak from this path is prompt injection. Mitiga showed planted instructions https://www.mitiga.io/blog/poisoned-coding-test-ai-agent-attack leading Cursor, with auto-run on, to read ~/.aws/credentials and send it out over MCP. Mitiga describes it as an incident it observed, without naming the victim, and I found no other documented case of an agent sending out another tool's credentials. Test: scan the agents' own directories. trufflehog filesystem ~/.claude ~/.codex ~/.config/opencode ~/.local/share/opencode --results=verified,unknown Fix: in Claude Code, add Read ./.env and Read ./.env. deny rules https://code.claude.com/docs/en/permissions ; a .claudeignore file does nothing. In Codex, set shell environment policy.ignore default excludes = false so variables named like keys stay out of subprocesses. Shorten transcript retention with cleanupPeriodDays . An old Google key gained Gemini access Google API keys starting with AIza were long treated as public identifiers for Maps or Firebase. Truffle Security https://trufflesecurity.com/blog/google-api-keys-werent-secrets-but-then-gemini-changed-the-rules showed in February 2026 that the same keys authenticate to Gemini once the Generative Language API is enabled on the project, and found 2,863 live vulnerable keys in public web data. The Register reported in March https://www.theregister.com/security/2026/03/03/dev-stunned-by-82k-gemini-api-key-bill-after-theft/4925029 that a three-developer startup was billed $82,314 for a Gemini key stolen in February. Test: in the Google Cloud console, check whether the Generative Language API is enabled and which keys have no restrictions. Fix: restrict every key to the APIs and apps that use it. Google now blocks unrestricted keys https://ai.google.dev/gemini-api/docs/api-key on the Gemini API. Spend caps and scopes that limit the damage A hard spend cap is the one control that limits the bill when a key leaks; an alert only reports it. Anthropic, OpenAI, OpenRouter https://stackness.dev/tools/openrouter and Google Cloud https://stackness.dev/tools/google-cloud now all offer a hard cap; of the four, only OpenRouter caps a single key. AWS has no Bedrock spend cap, only a budget action that attaches a deny policy you write yourself, and a Google Cloud alerts-only budget does not stop traffic. | Provider | Hard cap | Where it applies | |---|---|---| | Anthropic https://platform.claude.com/docs/en/api/rate-limits | Yes | Organisation or workspace spend limit; not the default workspace | | OpenAI https://developers.openai.com/api/docs/guides/spend-limits | Yes, with "Enforce a hard limit" switched on | Organisation or project | | OpenRouter https://openrouter.ai/docs/api-reference/authentication | Yes | Each key, with a daily, weekly or monthly reset | | Google Cloud https://docs.cloud.google.com/billing/docs/how-to/budgets-spend-caps | Yes, since 13 October 2026 | Each project and service, Gemini API included | | LiteLLM virtual keys | Yes, only with a database behind the proxy | Each key, max budget and budget duration | | AWS Budgets | No, alerts and actions | An action can attach an IAM policy that denies Bedrock; no built-in cap | None of the caps is instant: OpenAI and Google both say small overruns get through, and Google raised one victim's billing tier automatically during an attack. Two backstops help after the fact. GitHub https://stackness.dev/tools/github secret scanning reports leaked keys https://docs.github.com/en/code-security/reference/secret-security/supported-secret-scanning-patterns to OpenAI, Anthropic, OpenRouter, Google, xAI and Groq. And scanners do not cover every key: Gitleaks https://stackness.dev/tools/gitleaks has no OpenRouter rule, and neither Gitleaks nor TruffleHog https://stackness.dev/tools/trufflehog recognises a LiteLLM sk- key, so search agent configs for sk- values by hand. On Stackness, as of 30 October 2026, OpenCode is on 3 real public stacks and LiteLLM, Gitleaks and Railway on none how I count https://stackness.dev/about/data-sources ; the keys live in the AI coding tools developers list https://stackness.dev/categories/ai-tools . If you see this, check that | You see | Check | Fix | |---|---|---| | A key in a public repo, or a GitHub or provider revocation email | git ls-files for agent configs, gitleaks git --log-opts="--all" | Revoke the key; switch configs to {env:VAR} or ${VAR} | | A bill spike with nothing committed | Every hosting platform and agent console holding a key; Railway and OpenCode Console notices | Revoke at the provider; one capped key per tool | | A key visible in the browser | grep the build output for key prefixes | Move the call server-side, rotate, drop source maps | | A key inside a published package | npm pack --dry-run for .claude/ and friends | files allowlist; never approve commands with inline keys | | A key in an agent transcript | trufflehog filesystem ~/.claude ~/.codex | Read deny rules for .env ; shorter retention | | Gemini charges on a Maps or Firebase key | Enabled APIs and unrestricted keys in Google Cloud | Restrict every key | | Any of the above, before it happens | A hard cap on every key and workspace | Anthropic workspace limit, OpenAI hard limit, OpenRouter key limit, Google spend cap | New posts by email About one email a week with what we published. No account needed. Which of these do you use? Nobody on Stackness runs Railway yet. Tick what you use and be the first. Play Lonny Eagle Amateur Skater 4A pixel art skateboarding game. Signing up opens it straight away.Sign up to play https://stackness.dev/games/lonny-eagle