A Japanese dev just got billed roughly $60,000 (~9 million yen) in 13 hours because a Google API key leaked from their Firebase + Gemini app. I saw the post trending on Qiita this morning and my stomach dropped — not because it's a new story, but because I've seen the exact same mistake every single week while building CodeHeal, my security scanner for AI-generated code.
The key was exposed. The key had no referrer restriction. An attacker found it, pointed it at Gemini, and burned through the budget in hours. That's it. That's the whole "hack."
This is the #1 way AI-accelerated projects get wiped out in 2026, and no one is talking about it enough.
What actually happened
The short version:
- A solo dev shipped a Firebase + Gemini app
- The Google API key landed in the frontend bundle (very common — Firebase web SDKs literally ask you to paste it there)
- The key had no Application restriction and no API restriction
- Someone scraped it, pointed it at Gemini, and racked up ~9,000,000 JPY (~$60K USD at today's 159 USD/JPY) in 13 hours
- Google's abuse detection did not kick in fast enough
The bill landed before the dev finished their morning coffee.
Why this is so much worse in the AI-generated-code era
I built CodeHeal specifically because I kept watching this pattern unfold. After running the scanner on a bunch of Claude-generated and Copilot-generated repos, here's what I noticed:
1. LLMs love to "just make it work."
When you ask an AI "wire up Firebase + Gemini in my Next.js app," the path of least resistance is a client-side config object with the raw key. It compiles, the demo works, the dev ships. The LLM rarely stops to say "by the way, this key is now public — did you restrict it?"
2. Firebase's own docs muddy the water.
The Firebase web config is technically meant to be public — but that's only safe if you lock the key down with restrictions and rely on Firebase Security Rules. When the same key is unrestricted and has Gemini API access attached, you've built a tap someone else can open.
3. The feedback loop is broken.
You don't learn the key leaked until the bill lands. No CI alarm, no typecheck, no test failure. This is the exact category where static analysis earns its keep.
During CodeHeal's early testing I ran it on ~40 public "Firebase + AI" starter repos cloned off GitHub. 32 of them had at least one exposed key or a Firebase config with missing restrictions sitting in plain text. That's 80%. I wasn't cherry-picking — these were starters from the first two pages of GitHub search.
That was the moment I stopped writing the scanner as a side project and started writing it as a product.
Why I didn't use an LLM to detect this
When I first prototyped CodeHeal I tried the obvious thing: feed the repo to a model and ask it to flag secrets. I ran the same input 5 times. I got 5 different answers. Sometimes it missed the hardcoded key entirely. Sometimes it hallucinated a "leaked JWT" that didn't exist. Once it told me process.env.NEXT_PUBLIC_API_KEY was safe because it used env vars — which is exactly the bug that bills you $60K, because NEXT_PUBLIC_* ships to the browser.
That was the day I ripped the LLM out and rewrote the engine as pure static analysis — AST walks, pattern matching, and rule-based heuristics. The detection is now deterministic: the same input always produces the same output. For a security tool, that is table stakes. I'm frankly surprised more of the "AI security" scanners on the market still run LLM-in-the-loop.
CodeHeal currently ships 14 categories and 93 rules. The hardcoded-secret / unrestricted-credential category is the one that keeps paying for itself.
What you should actually do today
If you have a Firebase + AI app in production right now, here is the 10-minute checklist:
- Open Google Cloud Console → APIs & Services → Credentials. Every API key should have BOTH an Application restriction (HTTP referrer, IP, or Android/iOS app) AND an API restriction (limit which APIs it can call). Both. Not one.
-
Check your frontend bundle. Open the built JS and search for
AIza— that's the prefix for Google API keys. If you find one without a referrer lock, rotate it now, not after standup. - Budget alerts are not optional. Set a hard billing cap at a number that won't destroy you. Google's default is nothing.
- Gemini/Vertex keys should never, ever be in the client. Proxy through a backend route. I don't care how prototypey your project is.
- Run a scanner before every push. Not after. Before.
How CodeHeal handles this category
Without giving away the rule definitions (the detection logic is the product), here's the shape of it:
- We look for key-like literals in source files that ship to the client (Next.js
NEXT_PUBLIC_*, ViteVITE_*, CRAREACT_APP_*, plus raw string patterns) - We cross-reference against known provider prefixes (Google, OpenAI, Anthropic, Stripe, etc.) with different confidence levels
- We check for framework-specific footguns — the Firebase config object, hardcoded Vercel env values committed to repo,
.env.localfiles accidentally tracked - Findings are ranked by blast radius, not by count. One exposed Gemini key > a hundred cosmetic warnings
On a Firebase + Gemini Next.js archetype app, a CodeHeal scan runs in under 2 seconds and flags the unrestricted-key pattern as Critical. The dev in the $60K story would have seen the warning on their first git push.
The uncomfortable truth
AI lets you ship in an afternoon what used to take a week. It also lets you leak a production credential in an afternoon. The speedup is symmetrical — and the billing systems of Google, OpenAI, Anthropic, and every other AI provider are not going to save you. They are explicitly built to not save you, because usage is revenue.
Static analysis is the cheapest insurance you will ever buy for a vibe-coded AI app.
Summary
| What | Details |
|---|---|
| Incident | ~$60K billed in 13 hours via leaked Google API key (Firebase + Gemini app) |
| Root cause | Unrestricted API key shipped to client |
| Why AI code makes it worse | LLMs optimize for "works in demo," not for secret hygiene |
| Fix in 10 min | Application + API restrictions, billing cap, proxy Gemini through backend |
| Longer fix | Deterministic static scan in CI before every push |
If you want to see what a scan of your own AI-generated repo turns up, CodeHeal runs in the browser, no signup for the free tier:
👉 Scan your repo free on CodeHeal
5 scans/day on the free plan. 14 categories, 93 rules, no LLM, same result every time. If it finds an unrestricted API key in your code, you'll know before a scraper does.
This article was originally published by DEV Community and written by ayame0328.
Read original article on DEV Community