August 25, 2026
From Google Maps to Gemini: How One API Key Created a $375,000 Cloud Bill
A security incident that started with a simple API key and ended with a financial impact of nearly Rp6 billion.

By Randi Adhityas Saputra
10 min read
Sometimes the most expensive cloud incidents don't start with a sophisticated attack.
There was no zero-day vulnerability.
No compromised service account.
No complex infrastructure breach.
In this case, the problem was something much simpler:
An API key that was never supposed to be used for AI was left unrestricted.
The key had originally been used for public-facing services such as Google Maps or YouTube. At some point, it became exposed and compromised.
Then the project enabled the Gemini API.
Because the API key belonged to the same Google Cloud project and wasn't properly restricted, an attacker could use that key to generate Gemini API requests.
The result was a massive and unexpected financial impact.
Within only a few days, the project accumulated approximately Rp6 billion in API charges — roughly US$350,000–$400,000, depending on the exchange rate.
This incident was a painful reminder that an API key is not just an application configuration value.
In a cloud environment, an exposed credential can become a direct path to your billing account.
The Background: A Project With More History Than Anyone Expected
Like many long-running cloud projects, this project had accumulated API keys over time.
Some were actively used.
Some belonged to older applications.
Some had been created for services such as:
- Google Maps
- YouTube APIs
- Firebase
- Other public-facing Google APIs
The problem wasn't necessarily that these APIs existed.
The problem was that some keys had survived without proper restrictions.
An API key can be configured with restrictions that limit:
- Who can use the key
- Website referrers
- IP addresses
- Android applications
- iOS applications
2. Which APIs the key can call
- Google Maps APIs
- YouTube Data API
- Other explicitly approved APIs
But a legacy key can sometimes remain in an unrestricted state.
And if that key is exposed somewhere public — such as:
Frontend JavaScript
Mobile application
Public Git repository
Old source code
Client-side configuration
Historical deployment artifactFrontend JavaScript
Mobile application
Public Git repository
Old source code
Client-side configuration
Historical deployment artifact— it should be considered potentially compromised.
The dangerous part came later.
Then Gemini API Was Enabled
The project eventually enabled the Gemini API.
From the application's perspective, this seemed unrelated to the existing Maps or YouTube API keys.
But from the perspective of the Google Cloud project, those credentials and APIs were now part of the same environment.
The simplified situation looked like this:
GOOGLE CLOUD PROJECT
┌─────────────────────────────────────────────────────┐
│ │
│ Existing API Key │
│ ┌──────────────────────────────┐ │
│ │ API Key: ABC123... │ │
│ │ │ │
│ │ Application Restriction: ❌ │ │
│ │ API Restriction: ❌ │ │
│ └──────────────┬───────────────┘ │
│ │ │
│ │ Can potentially call │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Google APIs │ │
│ │ │ │
│ │ Maps │ │
│ │ YouTube │ │
│ │ Gemini API ← NEW │ │
│ └───────────┬───────────┘ │
│ │ │
└────────────────────┼────────────────────────────────┘
│
▼
ATTACKER / ABUSER
│
▼
Gemini API Requests
│
▼
💸 BILLING SPIKEGOOGLE CLOUD PROJECT
┌─────────────────────────────────────────────────────┐
│ │
│ Existing API Key │
│ ┌──────────────────────────────┐ │
│ │ API Key: ABC123... │ │
│ │ │ │
│ │ Application Restriction: ❌ │ │
│ │ API Restriction: ❌ │ │
│ └──────────────┬───────────────┘ │
│ │ │
│ │ Can potentially call │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Google APIs │ │
│ │ │ │
│ │ Maps │ │
│ │ YouTube │ │
│ │ Gemini API ← NEW │ │
│ └───────────┬───────────┘ │
│ │ │
└────────────────────┼────────────────────────────────┘
│
▼
ATTACKER / ABUSER
│
▼
Gemini API Requests
│
▼
💸 BILLING SPIKEThe attacker didn't need access to the Cloud Console.
They didn't need a service account.
They didn't need IAM permissions.
They only needed a usable API key.
And because the key had no proper API restrictions, it became possible to abuse it against an expensive AI service enabled within the same project.
The Financial Impact
The abuse did not look like a normal application workload.
Gemini API usage can consume requests and tokens extremely quickly.
Rate limits help regulate usage through dimensions such as requests per minute, tokens per minute, and requests per day, but rate limits are not the same thing as a hard financial budget. They also depend on the project's usage tier and the model being used.
In this incident, the attacker was able to generate enough usage that the financial impact reached approximately:
Rp6,000,000,000
Using a rough exchange rate of Rp16,000 per US dollar, that is approximately:
US$375,000
And the most alarming part was not just the total.
It was the speed.
A cloud bill that normally grows gradually can change dramatically when an exposed credential is used to access a high-consumption generative AI service.
Traditional monitoring is often designed around infrastructure.
CPU spikes.
Memory spikes.
Disk utilization.
Network traffic.
But generative AI introduces a different type of risk.
A relatively small number of API clients can generate enormous cost depending on:
- Model selection
- Input token size
- Output token size
- Request volume
- Context window size
- Batch or automated workloads
This means:
A credential security incident can become a FinOps incident almost immediately.
The Root Cause Was Not Gemini
It would be easy to describe this as a "Gemini problem."
But that would miss the actual lesson.
The root cause was a combination of several conditions.
1. An API Key Was Exposed
The key was available somewhere it should not have been.
Once an API key is exposed publicly, you should assume that someone else may already have a copy.
Deleting the repository later doesn't necessarily solve the problem.
Removing the key from the current version of the application doesn't guarantee that the key was never harvested.
Secrets have a long memory.
2. The API Key Was Unrestricted
The key lacked proper restrictions.
Instead of allowing only the intended API, the credential had broader access than necessary.
For example, a safer configuration for a Maps key would look conceptually like this:
API Key
Allowed Application:
✓ example.com
Allowed APIs:
✓ Maps JavaScript API
✓ Places API
Not Allowed:
✗ Gemini API
✗ Generative Language API
✗ Other unrelated APIsAPI Key
Allowed Application:
✓ example.com
Allowed APIs:
✓ Maps JavaScript API
✓ Places API
Not Allowed:
✗ Gemini API
✗ Generative Language API
✗ Other unrelated APIsBut an unrestricted key effectively creates a much larger blast radius.
3. Gemini API Was Enabled in the Same Project
This was the missing piece that connected an old API key to a new financial risk.
The project contained:
Legacy API Key
+
No API Restriction
+
Gemini API Enabled
=
Potential Credential AbuseLegacy API Key
+
No API Restriction
+
Gemini API Enabled
=
Potential Credential AbuseThe API key may have been created years earlier for a completely different purpose.
But cloud projects evolve.
New APIs are enabled.
New services are introduced.
Old credentials remain.
And suddenly a credential that once represented a relatively small risk can become much more valuable to an attacker.
The Three-Condition Risk Model
The incident can be simplified into three conditions.
You should consider a project at risk if all three are true:
1. An API Key Is Exposed
For example:
- Public frontend
- Mobile application
- GitHub repository
- GitLab repository
- Old repository history
- Public configuration file
2. The API Key Is Unrestricted
The key does not have sufficient:
- Application restrictions
- API restrictions
3. Gemini API Is Available in the Same Project
The project can accept Gemini API usage that could potentially be associated with that credential.
┌──────────────────┐
│ Exposed Key │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Unrestricted │
│ API Access │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Gemini API │
│ Available │
└────────┬─────────┘
│
▼
HIGH RISK
│
▼
💸 BILLING ┌──────────────────┐
│ Exposed Key │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Unrestricted │
│ API Access │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Gemini API │
│ Available │
└────────┬─────────┘
│
▼
HIGH RISK
│
▼
💸 BILLINGIndividually, each condition may not immediately create a disaster.
Together, they can create a very expensive incident.
Why Budget Alerts Were Not Enough
This is another important part of the story.
Traditional Cloud Billing budgets are primarily an alerting mechanism.
They tell you that spending has crossed a threshold.
But an alert is not the same thing as stopping the workload.
Google's documentation explicitly distinguishes alerts-only budgets from spend caps: alerts-only budgets notify you, but do not automatically stop usage or spending.
At the time of this incident, the available protection was much more limited.
You could create something like:
50% Budget
│
▼
📧 Email Alert
80% Budget
│
▼
📧 Email Alert
100% Budget
│
▼
📧 Email Alert50% Budget
│
▼
📧 Email Alert
80% Budget
│
▼
📧 Email Alert
100% Budget
│
▼
📧 Email AlertBut the API could continue receiving requests.
If the attacker was generating requests faster than the billing data was being processed and reviewed, the financial damage could continue growing.
This is one of the difficult realities of cloud cost management:
Visibility is not the same as enforcement.
Three Months Later, Google Introduced a New Safety Net
The timing is interesting.
Google Cloud has since introduced Spend Cap Budgets, currently available as a Preview feature for eligible services.
For supported services, including Gemini API, a spend cap can automatically pause new usage when the configured spending threshold is reached. Google Cloud also notes that enforcement uses estimated costs and is not instantaneous, so some overage can still occur.
Conceptually, the protection now looks like this:
Gemini API Usage
│
▼
┌──────────────────────┐
│ Monthly Spend Cap │
│ │
│ Limit: $10,000 │
└──────────┬───────────┘
│
│ Spend reaches limit
▼
┌──────────────────────┐
│ SPEND CAP ENFORCED │
│ │
│ New Gemini API │
│ usage is paused │
└──────────────────────┘Gemini API Usage
│
▼
┌──────────────────────┐
│ Monthly Spend Cap │
│ │
│ Limit: $10,000 │
└──────────┬───────────┘
│
│ Spend reaches limit
▼
┌──────────────────────┐
│ SPEND CAP ENFORCED │
│ │
│ New Gemini API │
│ usage is paused │
└──────────────────────┘This is significantly different from a normal budget alert.
Instead of:
"Your spending has exceeded the budget."
The system can move closer to:
"The spending threshold has been reached, so new billable usage is paused."
According to the current documentation, spend caps can be configured for a single project and a single eligible service, and Gemini API is among the supported services. The service remains paused until the cap is manually lifted.
This would not replace credential security.
And it would not guarantee a bill of exactly zero beyond the cap because enforcement is not instantaneous.
But it adds an important financial circuit breaker.
Rate Limits Are Not a Financial Firewall
Another important lesson from this incident is that rate limiting and cost limiting solve different problems.
Gemini API rate limits control dimensions such as:
RPM → Requests Per Minute
TPM → Tokens Per Minute
RPD → Requests Per DayRPM → Requests Per Minute
TPM → Tokens Per Minute
RPD → Requests Per DayThere are also spend-based rate limits tied to usage tiers.
But none of these should be treated as your only protection against unexpected financial exposure.
A system can remain technically within its permitted API rate limits and still generate a large bill.
For cloud engineers, these are different layers:
┌────────────────────────────────────┐
│ Layer 1 │
│ Credential Security │
│ │
│ Restrict API Keys │
├────────────────────────────────────┤
│ Layer 2 │
│ API Restrictions │
│ │
│ Allow Only Required APIs │
├────────────────────────────────────┤
│ Layer 3 │
│ Application Restrictions │
│ │
│ Referrer / IP / Mobile App │
├────────────────────────────────────┤
│ Layer 4 │
│ Rate Limits and Quotas │
│ │
│ Control Request Volume │
├────────────────────────────────────┤
│ Layer 5 │
│ Cost Monitoring │
│ │
│ Budgets + Anomaly Detection │
├────────────────────────────────────┤
│ Layer 6 │
│ Financial Circuit Breaker │
│ │
│ Spend Cap │
└────────────────────────────────────┘┌────────────────────────────────────┐
│ Layer 1 │
│ Credential Security │
│ │
│ Restrict API Keys │
├────────────────────────────────────┤
│ Layer 2 │
│ API Restrictions │
│ │
│ Allow Only Required APIs │
├────────────────────────────────────┤
│ Layer 3 │
│ Application Restrictions │
│ │
│ Referrer / IP / Mobile App │
├────────────────────────────────────┤
│ Layer 4 │
│ Rate Limits and Quotas │
│ │
│ Control Request Volume │
├────────────────────────────────────┤
│ Layer 5 │
│ Cost Monitoring │
│ │
│ Budgets + Anomaly Detection │
├────────────────────────────────────┤
│ Layer 6 │
│ Financial Circuit Breaker │
│ │
│ Spend Cap │
└────────────────────────────────────┘Security and FinOps need to work together.
The Immediate Response
When investigating an incident like this, the first priority is to stop the abuse.
The response should generally look like this:
Step 1: Identify the Source of Consumption
Start with:
- Cloud Billing reports
- Service-level cost breakdown
- Gemini API usage
- API key usage
- Relevant logs and request patterns
Look for abnormal behavior such as:
Normal
───────▁▁▁▂▂▂▁▁▂
Abnormal
───────▁▁▁▂██████████Normal
───────▁▁▁▂▂▂▁▁▂
Abnormal
───────▁▁▁▂██████████The important question is:
Which project, service, credential, and workload is generating the cost?
Step 2: Revoke or Rotate the Compromised Key
Do not simply hide the key.
Do not assume changing a frontend configuration is enough.
If the key is compromised:
OLD KEY
│
▼
REVOKE / DELETE
│
▼
CREATE NEW KEY
│
▼
APPLY RESTRICTIONS
│
▼
DEPLOY SAFELYOLD KEY
│
▼
REVOKE / DELETE
│
▼
CREATE NEW KEY
│
▼
APPLY RESTRICTIONS
│
▼
DEPLOY SAFELYTreat the old key as permanently compromised.
Step 3: Restrict Every Remaining API Key
Every key should answer two questions:
Who is allowed to use this key?
For example:
Website:
example.com
Server:
203.x.x.x/32
Android:
Package + SHA certificate
iOS:
Bundle IDWebsite:
example.com
Server:
203.x.x.x/32
Android:
Package + SHA certificate
iOS:
Bundle IDWhich APIs is this key allowed to call?
For example:
Maps Key
✓ Maps JavaScript API
✓ Places API
✗ Gemini API
✗ Generative Language API
✗ YouTube API
✗ Everything elseMaps Key
✓ Maps JavaScript API
✓ Places API
✗ Gemini API
✗ Generative Language API
✗ YouTube API
✗ Everything elseThe principle is simple:
One key should have one clear purpose.
A Better Architecture: Don't Share Public API Keys With AI Workloads
One of the biggest architectural lessons from this incident is separation.
Instead of this:
ONE GOOGLE CLOUD PROJECT
┌───────────────────────────────┐
│ │
│ Public API Keys │
│ │ │
│ ├── Maps │
│ ├── YouTube │
│ └── Gemini │
│ │
│ Same Project │
│ Same Billing Exposure │
└───────────────────────────────┘ ONE GOOGLE CLOUD PROJECT
┌───────────────────────────────┐
│ │
│ Public API Keys │
│ │ │
│ ├── Maps │
│ ├── YouTube │
│ └── Gemini │
│ │
│ Same Project │
│ Same Billing Exposure │
└───────────────────────────────┘Consider stronger separation:
PROJECT A
Public Application APIs
Maps Key
YouTube Key
│
│ Restricted only to
│ required APIs
▼
PROJECT B
AI Workloads
Gemini API
Dedicated credential
Dedicated monitoring
Dedicated budget
Dedicated spend capPROJECT A
Public Application APIs
Maps Key
YouTube Key
│
│ Restricted only to
│ required APIs
▼
PROJECT B
AI Workloads
Gemini API
Dedicated credential
Dedicated monitoring
Dedicated budget
Dedicated spend capProject separation is not always required.
But separating workloads can reduce the blast radius.
If a public Maps API key is compromised, that should not automatically expose your generative AI budget.
What We Changed
After this incident, the approach to API key management changed.
The goal was no longer simply:
"Does the application work?"
The new question became:
"What happens if this credential is stolen?"
That led to a much stronger checklist.
1. Audit Every API Key
For every key:
Owner?
Purpose?
Application?
Allowed APIs?
Restriction?
Last used?
Still required?Owner?
Purpose?
Application?
Allowed APIs?
Restriction?
Last used?
Still required?If nobody can explain why a key exists:
Delete it.
2. Remove Unrestricted Keys
Unrestricted keys should be treated as technical debt.
Especially old keys.
Especially keys that were created before current security practices were established.
Google's current Gemini API documentation is also moving toward stronger key controls: it states that unrestricted standard keys are rejected for Gemini API requests, and new AI Studio keys are created as auth keys by default. The documentation also describes additional migration and restriction requirements for standard keys.
That is an important improvement, but organizations should not wait for platform defaults to protect every historical credential.
3. Use Dedicated Credentials
Avoid this:
ONE KEY
│
├── Maps
├── YouTube
├── Firebase
└── AIONE KEY
│
├── Maps
├── YouTube
├── Firebase
└── AIPrefer:
Maps Key
└── Maps APIs only
YouTube Key
└── YouTube APIs only
Gemini Credential
└── Gemini onlyMaps Key
└── Maps APIs only
YouTube Key
└── YouTube APIs only
Gemini Credential
└── Gemini onlySmaller permissions mean a smaller blast radius.
4. Enable Financial Guardrails
For Gemini workloads, configure multiple layers:
GEMINI API
│
▼
┌─────────────────┐
│ Rate Limits │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Budget Alerts │
│ 50% / 80% / ... │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Cost Anomaly │
│ Detection │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Spend Cap │
│ Financial Stop │
└─────────────────┘ GEMINI API
│
▼
┌─────────────────┐
│ Rate Limits │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Budget Alerts │
│ 50% / 80% / ... │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Cost Anomaly │
│ Detection │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Spend Cap │
│ Financial Stop │
└─────────────────┘Google Cloud now supports spend cap budgets for Gemini API in eligible projects and billing configurations, providing an additional safety mechanism beyond traditional budget alerts.
The Bigger Lesson: AI Changes the Cost of Credential Exposure
Before generative AI, an exposed API key might create:
- Unexpected Maps API usage
- YouTube quota abuse
- API quota exhaustion
Those were already serious problems.
But generative AI changes the financial equation.
A compromised credential can now be used to consume:
- Large language model inference
- Large context windows
- High-volume automated prompts
- Expensive model workloads
The attacker's infrastructure cost is effectively close to zero.
The victim pays.
This changes the threat model.
#Traditional Security Incident
Credential Leak
│
▼
Unauthorized Access
│
▼
Security Impact
Generative AI Incident
Credential Leak
│
▼
Unauthorized API Usage
│
▼
High-Volume AI Consumption
│
▼
💸 Financial Impact
│
▼
Security + FinOps Incident#Traditional Security Incident
Credential Leak
│
▼
Unauthorized Access
│
▼
Security Impact
Generative AI Incident
Credential Leak
│
▼
Unauthorized API Usage
│
▼
High-Volume AI Consumption
│
▼
💸 Financial Impact
│
▼
Security + FinOps IncidentSecurity teams need to think about billing exposure.
FinOps teams need to think about credential exposure.
And cloud engineers need to design for both.
Final Thoughts
The most important lesson from this incident was surprisingly simple:
An API key should never be trusted just because it was created for a different API.
Cloud projects change.
New APIs are enabled.
Old credentials survive.
Applications are migrated.
Repositories are forgotten.
And technical debt quietly accumulates.
A key that was created years ago for Google Maps might not seem related to Gemini today.
Until suddenly, it is.
In our case, an unrestricted and compromised API key became part of a chain of events that resulted in approximately Rp6 billion of unexpected Gemini API usage.
There was no single catastrophic failure.
Instead, it was a combination of small gaps:
Legacy Key
+
No Restrictions
+
Credential Exposure
+
Gemini API Enabled
+
No Financial Hard Stop
=
Multi-Billion Rupiah IncidentLegacy Key
+
No Restrictions
+
Credential Exposure
+
Gemini API Enabled
+
No Financial Hard Stop
=
Multi-Billion Rupiah IncidentThe good news is that every part of that chain can be improved.
Restrict your API keys.
Separate workloads where appropriate.
Rotate exposed credentials.
Monitor AI-specific costs.
Use anomaly detection.
Set budgets.
And where available, configure spend caps.
Because in the age of generative AI:
Your API key is no longer just a key to an API.
It may also be a key to your cloud budget.