Public API keys: lock down the key that's visible in your page
A browser API key is safe to expose only if it's restricted by domain, scope, and quota, otherwise someone else spends your budget
The threat
The scanner found an API key sitting in your page’s client-side code, something like a AIza… Google Maps key or a Stripe pk_live_… publishable key. Here’s the honest part: many browser keys are designed to be public. A Maps or Stripe publishable key has to ship to the browser to work at all, so seeing one in your source is not automatically a leak.
The real question is whether it’s restricted. An unrestricted public key is a blank check: anyone can copy it out of your page and use it from their own site, running up your bill or burning through your quota until your maps stop loading or a budget alert fires. And if the flagged key turns out to be a genuine secret (an sk_… secret key, a private token), that’s a more serious problem, and it needs to leave the client entirely.
The exact fix
First, work out which kind of key it is.
- A publishable or browser key (Google Maps
AIza…, Stripepk_…, a Firebase web config): meant to be public. Your job is to restrict it, see below. - A secret key (Stripe
sk_…, a server-side API key, any token the docs say to keep server-only): it should never be in client code. Treat it as burned: rotate it now in the provider console, and serve whatever it protected from your own server (a backend endpoint or serverless function), never the browser.
Restrict a public key in the provider console (Google Cloud, Stripe, and so on):
- Lock it to your domain. Add an HTTP-referrer or allowed-origins restriction so the key only works from
https://yourdomain.com/*. Pasted onto someone else’s site, it then does nothing. - Limit it to the exact APIs it needs. A Maps key should call the Maps APIs and nothing else, not your whole cloud project.
- Set a quota and a budget alert. Cap daily usage and turn on billing alerts, so abuse hits a ceiling and pings you instead of your invoice.
If it ran unrestricted for any length of time, rotate it as well. Assume it’s already been scraped. Generate a new key, apply the restrictions above to it from the start, then retire the old one.
Restriction lives in the provider’s console, not your code. Editing the key in your HTML changes nothing about who can use it. And never move a secret key into client code to “match” a public one, the fix runs the other way: secrets belong on the server.
Verify it
curl -s https://yourdomain.com | grep -ioE 'sk_live_[0-9a-zA-Z]+|sk_test_[0-9a-zA-Z]+'
No output means no Stripe secret key is shipping to the browser (that pattern should never appear, and if it does, rotate immediately). For a public key, the real confirmation is in the provider console: it shows an HTTP-referrer restriction scoped to your domain, an API allowlist, and a usage quota. Quick functional check: use the key from a domain that isn’t yours, and a properly restricted key gets rejected.
Proof
The ApeCyber scanner reads your public page source the same way any visitor can, passively, from the outside, touching nothing, and flags keys it finds so you can confirm they’re restricted (it never tests or uses the key). apecyber.com and dev3lop.com grade A / 100 with no unrestricted secrets shipping to the browser. Restricting or rotating a key is a 5-minute, −4 cleanup that turns a blank check into a domain-locked, budget-capped one.