← 목록

MCP configs are the new .env files — I found live database keys committed on GitHub

devto 2026-10-21 원문 보기 ↗


MCP configs are the new .env files. I scanned GitHub and found live database keys committed in public repos.

If you use Claude Desktop, Claude Code, Cursor or Windsurf with external tools, you have an .mcp.json or claude_desktop_config.json file on your machine. It tells your editor which MCP servers to start, and each server entry can carry an env block.

That env block is a secret store. And developers are pasting real keys into it — then committing the file.

What I found

I ran GitHub code search for filename:.mcp.json SUPABASE_SERVICE_ROLE and similar queries, then verified every result instead of trusting the match:

  1. Decode, don't pattern-match. A file only counts if it contains a JWT whose decoded payload literally says "role": "service_role". In my scan, 53 of 65 candidate files were placeholders, templates or examples. If I had emailed all 65, four out of five would have been noise — the fastest way to teach someone to ignore security reports.
  2. Probe whether the project is live. A leaked key for a deleted Supabase project is worthless. A GET https://<ref>.supabase.co/rest/v1/ that answers 401 (no credentials sent, nothing read) proves the project is live and the key is valid until rotated.

The result: 12 files in public repos contain a real, decodable service_role key. 4 of those projects are live right now. One of them was pushed the same day I scanned.

A service_role key bypasses every row-level-security policy. Whoever finds it has full read/write access to the database — not "some" access, all of it.

Why this keeps happening

The mental model is wrong, not the people. .mcp.json feels like editor configuration — like settings.json, like .vscode/. Nobody expects a linter or a framework to warn them, because no tool in this ecosystem treats the file as a secret store yet.

Compare with .env: a decade of leaked keys produced pre-commit hooks, secret scanners, CI checks, and platform warnings. .mcp.json has none of that guardrail history, so the same 2015-style mistakes are being made again in 2026 — just with database keys that grant more access than most API keys ever did.

Deleting the file doesn't help either: git history keeps every version forever. The only fix that works is rotating the key (Supabase Dashboard → Settings → API → rotate), then moving the new value into a runtime environment variable.

I built the linter I wanted to exist

I've spent months doing Supabase RLS audits. The configuration side of this problem needs zero-expertise tooling, so I built a family of zero-dependency auditors. Each one runs locally, reads nothing from the network, and redacts evidence in its reports so the report itself is safe to paste into an issue:

All free, all MIT, no accounts, no telemetry. The companion repo supabase-rls-leak-demo covers the database side: a fixture that goes red on a broken RLS policy and green on the one-file fix.

My own tool flagged my own CIs

The first thing I ran against my own four repos was github-actions-audit. It came back with 20 findings: every actions/checkout@v4 and actions/setup-node@v4 was a mutable tag, and none of the workflows had a permissions: block.

That is the correct experience for this class of tool — it should be slightly embarrassing. I resolved the action tags to their commit SHAs (git.ref/tags/v4), pinned all four workflows, added permissions: contents: read, and pushed. Same command now exits 0. If a security linter finds nothing on its first run against your config soup, be suspicious of the linter.

What to do tonight

If you have an .mcp.json or claude_desktop_config.json anywhere in a repo — or a NEXT_PUBLIC_ Supabase variable you're not sure about:

npx mcp-config-security
npx supabase-service-role-scanner .

Two commands, a few seconds, zero installs. If they come back clean, you're done. If they don't, rotate first, refactor second.

I reported the live leaks I found privately — no bounties asked, just the rotation. If one of these tools catches something real for you, you can buy me a coffee, but the tools stay free either way.