I found an API key in my HTML. What now?
Rotate first, investigate second. Then work out whether the key ever needed to be in the browser at all.
Assume it is compromised and rotate it immediately — anything served to a browser is public, regardless of obfuscation. Then check whether it needed to be there: some keys are designed to be public and restricted by origin, most are not.
Rotate first
Do not investigate before rotating. The key has been served to every visitor, every crawler and every archive that has fetched the page. It may be in the Wayback Machine and in search engine caches. Treat exposure as certain rather than probable.
- Generate a replacement key.
- Deploy the replacement wherever it is legitimately needed.
- Revoke the old one.
- Check the provider's access logs for use you do not recognise.
- Then work out how it got there.
Which keys are meant to be public
| Key type | Public? | Protection |
|---|---|---|
| Google Maps JavaScript key | Yes | Restrict by HTTP referrer and by API in the console. |
Stripe publishable key (pk_) | Yes | Designed for the browser. It cannot move money. |
| Firebase web config | Yes | Security comes from Firebase rules, not from hiding the config. |
| Analytics measurement IDs | Yes | Public by design. |
Stripe secret key (sk_) | No | Rotate immediately. It can charge cards. |
| Database credentials | No | Rotate, then audit access. |
| Cloud provider access keys | No | Rotate immediately. These get scanned for and abused within minutes. |
| Email or SMS API keys | No | Rotate. Abuse means your domain sends spam. |
The rule underneath
Anything the browser receives is public. Minification does not hide it, base64 does not hide it, splitting it across variables does not hide it. Someone reading your bundle finds it in seconds, and automated scanners find it faster.
So a key in the browser must be one where being public is acceptable — restricted by origin, scoped to harmless operations, or rate-limited. If it is not, it belongs on the server, with your front-end calling your own endpoint instead.
How they get there
- A build tool inlining the whole environment. Vite exposes anything prefixed
VITE_; Next.js exposes anything prefixedNEXT_PUBLIC_. Putting a secret behind those prefixes publishes it. - A developer testing quickly with a hardcoded key and never coming back.
- A server-side key imported into a file that is also bundled for the client.
- Configuration written into a data attribute or an inline script tag by a template.
- A committed
.env, later removed but still present in git history — and readable if.gitis exposed.
/.git/ is publicly readable — which is more common than it should be — the entire history including that key can be downloaded.Preventing recurrence
- Add secret scanning to your pipeline. Most hosted git providers offer it, and there are good standalone scanners.
- Use a pre-commit hook that refuses commits containing credential-shaped strings.
- Keep a hard rule that server secrets never carry a public build prefix.
- Restrict every key that must be public — by origin, by API, by rate limit.
- Confirm
/.git/and/.envare not web-readable. They should return 404.
What our audit reports about this
Every item below is measured directly, not inferred. Run it against your own site and the result names the exact rule or header responsible.
- Credential-shaped strings in HTML and inline scripts, reported redacted rather than in full.
- Whether
/.git/config,/.envand similar paths are publicly readable. - Every script loaded, with its origin, so third-party code is visible at a glance.
- Whether findings appear only in your report — exposed secrets are never stored or included in aggregate statistics.
For agents and scripts, the same measurement is at
/api/v1/security?url=yoursite.com —
see the API documentation.
Related questions
Is a Google Maps key in my HTML a problem?
Only if it is unrestricted. It is designed to be public, but an unrestricted key can be used from any site and billed to you. Restrict it by HTTP referrer and to the specific APIs you use.
Can I obfuscate a key so it is safe?
No. Obfuscation delays a curious person by minutes and an automated scanner by nothing. If a key must not be public, it must not be in the browser.
How would I know if a key was abused?
Check the provider's usage logs for requests from origins or regions you do not recognise, and for spikes. Set billing alerts. For cloud provider keys, assume abuse begins within minutes of exposure — these are actively scanned for.
Read next
Is my website secure? How do I check?
What you can verify yourself in twenty minutes, what needs tooling, and what "secure" does and does not mean.
ReadWhat is a Content Security Policy?
A list of where your page is allowed to load things from. The strongest defence against script injection, and the easiest header to get wrong.
ReadWhat are security headers and which do I need?
Six headers, what each actually prevents, and a configuration you can paste and adjust.
ReadShould I put my email address on my website?
Yes. The spam argument is weaker than it was, and being uncontactable costs more than the spam does.
Read