Secrets

Google API keys & GCP service-account JSON in the open

Two very different things called 'Google credentials'

People lump Google credentials together, but two common ones carry wildly different risk, and confusing them is how the worse one leaks. Let us separate them first.

The Google API key

A Google API key is a single string — something like AIza... — that authorizes requests to a particular Google service: Maps, the YouTube data API, and so on. Some Google APIs are designed to be called from the browser, so the key being visible is not automatically a disaster. But that is only true if the key is restricted.

An unrestricted API key is a problem. If anyone can copy it and use it from their own site, they can run up usage and bills against your account, or abuse quota-limited services on your dime. The defense is restriction:

  • Application restrictions — lock the key to your specific HTTP referrers (your domains) or IP ranges.
  • API restrictions — limit the key to only the exact APIs it needs, nothing else.

A tightly restricted Maps key in your frontend is acceptable. A wide-open one is a liability even though it 'belongs' in the browser.

The GCP service-account JSON

This is the dangerous one, and the two should never be confused. A GCP service-account key is a JSON file containing a private key and an identity. It is meant for server-to-server authentication — your backend proving it is allowed to talk to Google Cloud. It often carries broad permissions: read and write to storage buckets, query databases, manage resources.

That file is a master key. It has the telltale shape — fields like "type": "service_account", "private_key", "client_email" — which makes it instantly recognizable to scanners. If it leaks, whoever holds it can authenticate as that identity and do whatever its roles allow. There is no 'but it is restricted to my domain' here; a service-account JSON has no business being anywhere near the browser, ever.

Where both leak

The same tired paths catch them:

  • In the frontend bundle — a service-account JSON imported into client code, or an unrestricted API key hardcoded there.
  • Committed to a repo — the JSON file checked in, then the repo goes public or is forked.
  • In a public folder — the file deployed as a static asset, one predictable URL away.
  • In logs or error traces — the credential printed during a failure.

How to lock them down

  • Restrict every API key by referrer/IP and by API. Treat an unrestricted key as already abused.
  • Keep service-account JSON server-side only, in a secrets manager or environment configuration — never in code that ships, never in a public folder.
  • Prefer keyless auth where available — workload identity and similar mechanisms avoid having a long-lived JSON key at all.
  • Rotate anything exposed. Delete the leaked key in the Google console, issue a new one, and check usage logs for activity you do not recognize.

Check what your site exposes

A service-account JSON or an unrestricted key buried in a bundle is invisible to a quick look. An automated scan reads your pages and scripts the way a bot would and flags Google keys and service-account credentials reachable from the browser. Scan your site and find out before someone bills your cloud account.

Related reading

FAQ

Is it ok to put a Google API key in frontend code?
Only if it is tightly restricted. Some Google APIs are meant to be called from the browser, so a key locked to your domains and limited to the specific APIs it needs is acceptable. An unrestricted key in the frontend can be copied and abused against your account.
Why is a GCP service-account JSON so much worse than an API key?
It contains a private key and authenticates as an identity that often has broad cloud permissions — read/write storage, databases, resources. It is a server-only master credential and must never appear in client code, a public folder, or a committed repo.
I leaked a service-account key — what now?
Treat it as fully compromised. Delete the key in the Google Cloud console immediately, issue a new one, move it into a secrets manager, and review the audit logs for activity you do not recognize. Consider keyless workload identity to avoid long-lived JSON keys.