Leaked API keys in the browser: what to look for
Leaked secrets are API keys, tokens and private credentials shipped to the browser in HTML, scripts or source maps. How they leak and what to do first.
Leaked secrets are credentials, such as API keys, access tokens, database URLs or private keys, that end up in something the browser downloads: the HTML, a JavaScript bundle or a source map.
Anything sent to the browser is public. A key in a minified bundle can be read by anyone who opens the developer tools, and automated scanners look for them. OWASP’s testing guide treats reviewing page content and scripts for leaked information as a standard step. Source maps are a related exposure. MDN describes them as files that map transformed code back to the original source, so a public map hands out the readable code, including comments and internal paths. Not every key in a page is a leak, though. Some are public by design, such as a maps or analytics key restricted to one domain.
Category: Security
Why it matters
A leaked server-side key works for whoever finds it, and the bill or the breach lands on the site owner. The usual cause is a build tool inlining an environment variable into the client bundle, a framework’s public-variable prefix used on the wrong name, or a debugging line left in a template. Development leftovers cause smaller leaks of the same kind: links to localhost, private IP addresses and preview hosts that reveal internal infrastructure.
How squirrelscan checks it
security/leaked-secrets scans the HTML of every crawled page, every inline script and the external JavaScript files the crawl fetched, against about ninety patterns for AI providers, cloud platforms, payment processors, databases and generic api_key = "..." assignments. It fails on high-confidence matches and on server-only secrets in browser-served scripts, and warns on medium-confidence ones to verify by hand. Keys that are public by design are listed at info level and never count as leaks. Every reported value is masked. perf/source-maps finds sourceMappingURL comments and SourceMap headers that point to a map. It does not fetch the map, so it reports possible exposure rather than proving it. content/dev-leakage finds references to localhost, private IP ranges, local-only names such as myapp.test, preview deployments and development subdomains on a production page.
| Rule | What it flags | Severity |
|---|---|---|
| Leaked API key in client-side code: how to find one | An API key shipped in HTML or a bundle can be read by anyone who views source. squirrel scans every page and script against 88 key patterns. | error |
| Exposed source maps: sourceMappingURL in production output | A sourceMappingURL comment or SourceMap header pointing at a map anyone can fetch. squirrel finds them in the page. | info |
| localhost in production: dev hosts left in the markup | A link or image pointing at localhost or a preview deployment is broken for every visitor. squirrel classifies the host and says whether it is yours. | warning |
How to fix it
Rotate the exposed credential first. It has been public since it shipped. Then move the call behind your own server:
// server route, not the client bundle
const res = await fetch("https://api.example.com/v1/data", {
headers: { Authorization: `Bearer ${process.env.EXAMPLE_SECRET_KEY}` },
});Read the key from an environment variable the bundler never inlines (the secrets fix). Build source maps as hidden, upload them to the error tracker and leave them out of the deploy (the source map fix). Replace development origins with relative paths (the dev leakage fix).
Run the check
squirrel audit https://example.com --rule-include security/leaked-secrets,perf/source-maps,content/dev-leakageA signed-out local audit costs nothing.
Related terms
- Token storage: Where a web app keeps session or auth tokens; tokens in localStorage are readable by any script on the page.