API TOKEN LEAK CHECKER
Paste a URL. The scanner loads your live site and reads every JS bundle the browser fetched, fingerprinting 100+ key formats. If an attacker can open DevTools, they can see what we see.
FIND LEAKED API KEYS NOW
Enter your URL — we load the bundle in a headless browser and fingerprint Firebase, Stripe, AWS, OpenAI, Anthropic, Supabase, GitHub and 100+ more in under 30 seconds.
What is an API token leak?
An API token leak is when an API key, secret, or access token ends up inside code that every visitor can download — usually the JavaScript bundle. Anyone who opens browser DevTools can copy the key and use it from their own machine. Automated bots do this at scale: they crawl deployed sites, GitHub, and npm packages looking for known key formats, and they find new ones every minute.
This scanner finds those keys in under 30 seconds so you can rotate before a bot does. It is intentionally narrow: credentials in the browser surface. Pair it with the Vibe Code Scanner for authz and open-database classes that are not “keys” but still dump data.
Why token leaks happen to AI-generated apps
AI coding tools — Lovable, Bolt, v0, Cursor, Claude Code, Replit — default to importing client SDKs directly into the frontend. That pattern ships your API key to every visitor. Keys that vendors label “safe for the client” (Stripe publishable, Supabase anon, Firebase config) are still abuse surfaces if the rest of your security model assumes no one has them. Keys that should never have shipped — OpenAI, Anthropic, Twilio, server-only Stripe — are catastrophic: one screenshot, one curl, and an attacker is billing your card.
Most of the vibe-coded apps we scan have at least one key in the frontend bundle that shouldn’t be there. See OWASP Top 10 for AI-generated code for the full pattern (especially A02 Cryptographic Failures).
How the generator creates the leak
- You prompt “add Stripe payments” or “call OpenAI for chat.”
- The model pastes the SDK example, which often includes
process.env.STRIPE_SECRET_KEYor a hard-codedsk-...placeholder. - In Vite/Next, someone renames the var to
VITE_/NEXT_PUBLIC_so “it works in the browser.” - The build inlines the value into a chunk. Deploy. Bots find it within hours.
The same loop produces service_role Supabase keys, Firebase service-account JSON, and AWS AKIA keys in public/ folders.
Host-specific accelerants
- Vercel / Next:
NEXT_PUBLIC_prefix is the classic footgun (Is Vercel Safe?) - Vite / Bolt:
VITE_inlining - Webflow custom code: secrets pasted into site-wide scripts (Is Webflow Safe?)
- Replit: secrets accidentally written into client files (Is Replit Safe?)
- Source maps: readable originals that make keys trivial to extract (Source Map Checker)
What the scanner checks
FIREBASE / FIRESTORE
API keys, project IDs, service account JSONs, and storage bucket credentials accidentally bundled into the client.
STRIPE
Secret keys (sk_live_…) in the frontend where only publishable keys belong, plus webhook secrets.
AWS / GOOGLE CLOUD
Access key IDs, secret keys, session tokens, signed URLs, and service-account JSON.
OPENAI / ANTHROPIC
LLM provider keys — usually mean you have exposed pay-per-token billing to the internet.
SUPABASE
Service-role keys where only the anon key belongs, and anon keys in front of tables with no RLS.
GITHUB / CI
Personal access tokens, fine-grained tokens, and CI secrets leaked through source maps or error pages.
Additional signatures typically include SendGrid, Twilio, Slack, Mapbox, and high-entropy bearer tokens. Treat any unexpected high-entropy string in a public chunk as guilty until proven to be a public client ID.
How it works
- Load — we fetch your URL in a real headless browser, the same way a user would.
- Capture — every JS file, inline script, source map, and XHR response gets inspected.
- Pattern match — 100+ known key signatures plus entropy-based detection for custom secrets.
- Report — each finding shows the source file, line number, key type, and remediation steps.
Because the browser is real, dynamically imported chunks and lazy routes still get pulled if the page loads them. For apps that only inject secrets after a deep navigation, also exercise those routes or run a fuller app scan.
Which keys are safe in the frontend?
| Key | Safe in browser? | Why |
|---|---|---|
Stripe publishable (pk_live_…) |
Yes | Designed to ship; restrict domain in Stripe dashboard. |
Stripe secret (sk_live_…) |
No | Full account access. Server-only. |
| Firebase Web config | Conditional | Safe only if Firestore Security Rules and Auth are correctly configured. |
| Firebase service account | No | Admin access to the entire project. |
Supabase anon key |
Conditional | Safe only if Row Level Security is enforced on every table. |
Supabase service_role key |
No | Bypasses RLS. Server-only. |
| OpenAI / Anthropic API key | No | Direct billing access. Always proxy through a backend. |
| AWS access key | No | Console and API access. Never ship to the browser. |
| Google Maps JS API key | Yes | Lock by HTTP referrer in Google Cloud Console. |
| GitHub PAT | No | Repo and org access. Never ship. |
| Slack bot token | No | Workspace access. Server-only. |
“Conditional” keys still need abuse controls: rate limits, referrer restrictions, and correct server-side policies. Public ≠ free-for-all.
Impact of the worst leaks
Stripe sk_live_: attacker creates charges, refunds, exports customers, changes payouts.
OpenAI / Anthropic: attacker burns your quota on cryptomining-style completions; bills hit five figures overnight without a hard cap.
Supabase service_role: full database dump/modify/delete; RLS is irrelevant.
AWS AKIA + secret: depending on IAM, full account takeover, crypto miners in your regions, public S3 dumps.
GitHub PAT: push malware to your repos, steal other secrets from Actions, pivot into org SSO apps.
Twilio / SendGrid: spam campaigns from your brand, phone fraud, reputation burn.
Rotate first, argue about severity later. Minutes matter more than perfect classification.
Common fixes
- Move keys to server-side code, edge functions, or backend proxies. The client should never hold a secret.
- For keys that must ship (Stripe publishable, Google Maps), restrict by origin/referrer in the provider dashboard.
- Rotate any key that ever appeared in a past deploy, GitHub commit, or log — bots already indexed it.
- Add a CI check that fails the build when a new token exposure is introduced.
- For Supabase, turn on RLS on every table before worrying about the anon key — RLS is the actual auth.
- Disable public source maps in production.
- Strip secrets from error pages and client-visible config endpoints.
Proxy pattern (Edge Function)
// Keep OPENAI_API_KEY only in server env
export async function POST(req: Request) {
const session = await getSession(req);
if (!session) return new Response("Unauthorized", { status: 401 });
const { prompt } = await req.json();
// rate-limit + validate prompt length here
const r = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({
model: "gpt-4o-mini",
messages: [{ role: "user", content: String(prompt).slice(0, 4000) }],
}),
});
return new Response(r.body, { headers: { "content-type": "application/json" } });
}
Local grep before every deploy
grep -rE 'sk_(live|test)_|sk-[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|xox[baprs]-' \
dist/ .next/static/ --include='*.js' || true
Any hit in dist/ or .next/static/ is a ship blocker.
CI gate sketch
- name: Fail on secret-shaped strings in build
run: |
if grep -rE 'sk_live_|sk_test_|service_role|AKIA[0-9A-Z]{16}' .next/static dist 2>/dev/null; then
echo "Possible secret in client build"
exit 1
fi
How to verify after rotation
- Rotate the key in the provider console (disable the old one completely).
- Remove the public prefix / move the call behind a server route.
- Rebuild with a clean cache (
rm -rf .next dist && npm run build). - Redeploy.
- Re-run this Token Leak Checker on the production URL.
- Search git history (
gitleaks detect --log-opts="--all") — if the key was committed, treat it as permanently public even after rewrite unless you rotate. - Check provider audit logs for usage from unexpected IPs between leak and rotation.
- Scan preview domains too — they often retain the old inlined values longer than you think.
Source maps: the silent amplifier
Production source maps (.js.map) make leaks easier to read and sometimes contain strings stripped from minified bundles. Disable public source maps for production builds, or host them behind auth for error-tracking only. The Source Map Checker flags public maps.
// next.config.js sketch
module.exports = {
productionBrowserSourceMaps: false,
};
What this scanner does not replace
- RLS / Security Rules — a public anon key with open tables is a data breach even when no “secret” key is present. Use the Supabase RLS Checker and Firebase Scanner.
- Server-side secrets in CI logs — we only see the browser surface.
- Keys behind login returned by APIs — run authenticated testing for those.
- Mobile app binary strings — different packaging; use mobile-specific secret scanning.
- Business-logic authz — BOLA is not a token leak; use full app scanning.
Incident playbook (first hour)
- Identify which key types appeared and in which chunk/URL.
- Rotate / revoke those keys in provider dashboards immediately.
- Kill billing risk: hard cap OpenAI/Anthropic; pause Stripe if needed.
- Remove public prefixes and redeploy clean builds.
- Audit logs for abuse between first deploy and rotation.
- Notify stakeholders if customer data or payment rails were exposed.
- Prevent with CI grep + ignore files + developer education on
NEXT_PUBLIC_.
Do not wait for a perfect root-cause document before rotating.
Logging, monitoring, and abuse (1)
Log authentication failures, authorization denials, and high-cost endpoints with request ids. Alert on spikes. Rate limit auth and AI proxy routes. For token-leak-checker, define what ‘abnormal’ looks like before an attacker teaches you under load.
# smoke verification sketch for token-leak-checker
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"
Dependency and supply chain (2)
Lockfiles, immutable CI installs, pinned GitHub Actions, and verification of packages the model suggests. Hallucinated package names are a real path. On token-leak-checker changes that touch package manifests, require a human to open the registry page once.
// deny-by-default sketch used near token-leak-checker
export function assertOwner(userId: string, ownerId: string) {
if (userId !== ownerId) throw new Error('forbidden');
}
Human process and training (3)
New engineers should break a demo app on purpose, fix it, and rescan. That training beats a PDF policy. For token-leak-checker, keep one golden path example of a secure change and one of a rejected insecure change in internal docs.
Operational checklist for token-leak-checker (4)
Treat token-leak-checker as a production surface with an owner, a review cadence, and a verification step after every AI-assisted change. Write the owner name in the repo SECURITY.md. Schedule a monthly re-read of controls that touch authentication, secrets, and data access. When an agent opens a PR against this area, require dual-user tests and a preview scan before merge. Keep a short incident appendix: which keys to rotate, which dashboards to check, who communicates with users.
# smoke verification sketch for token-leak-checker
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"
Common AI-generator mistakes on token-leak-checker (5)
Generators optimize for demos: open data paths, client-trusted roles, missing rate limits, and secrets in env files that ship to browsers. On token-leak-checker, re-check those classes after every feature prompt. Search diffs for deleted middleware, new admin routes, and dependency adds. Reject ’temporarily disable auth’ comments without a tracking ticket and expiry.
Verification commands and proofs (6)
Proof beats intention. For token-leak-checker, keep a script or checklist that demonstrates deny paths: anonymous access fails, user A cannot read user B, webhooks reject bad signatures, and bundles lack server secrets. Store the last run date next to the checklist. If the date is older than your release cadence, you are flying blind.
// deny-by-default sketch used near token-leak-checker
export function assertOwner(userId: string, ownerId: string) {
if (userId !== ownerId) throw new Error('forbidden');
}
CI and release gates (7)
Encode the minimum bar in CI so humans do not renegotiate under launch pressure: secret scan, dependency audit, unit tests including authz negatives, preview deploy, live security scan failing on criticals. For token-leak-checker-related paths, add CODEOWNERS so reviews land on people who understand the threat model.
# smoke verification sketch for token-leak-checker
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"
Environment separation (8)
Production credentials must not appear in previews or local agent sandboxes. Separate projects or branches for data stores, separate OAuth redirect allowlists, and separate Stripe test vs live keys. Document the matrix where coding agents can read it so ‘make preview work’ does not copy prod secrets again.
Logging, monitoring, and abuse (9)
Log authentication failures, authorization denials, and high-cost endpoints with request ids. Alert on spikes. Rate limit auth and AI proxy routes. For token-leak-checker, define what ‘abnormal’ looks like before an attacker teaches you under load.
Dependency and supply chain (10)
Lockfiles, immutable CI installs, pinned GitHub Actions, and verification of packages the model suggests. Hallucinated package names are a real path. On token-leak-checker changes that touch package manifests, require a human to open the registry page once.
# smoke verification sketch for token-leak-checker
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"
// deny-by-default sketch used near token-leak-checker
export function assertOwner(userId: string, ownerId: string) {
if (userId !== ownerId) throw new Error('forbidden');
}
Human process and training (11)
New engineers should break a demo app on purpose, fix it, and rescan. That training beats a PDF policy. For token-leak-checker, keep one golden path example of a secure change and one of a rejected insecure change in internal docs.
Operational checklist for token-leak-checker (12)
Treat token-leak-checker as a production surface with an owner, a review cadence, and a verification step after every AI-assisted change. Write the owner name in the repo SECURITY.md. Schedule a monthly re-read of controls that touch authentication, secrets, and data access. When an agent opens a PR against this area, require dual-user tests and a preview scan before merge. Keep a short incident appendix: which keys to rotate, which dashboards to check, who communicates with users.
Common AI-generator mistakes on token-leak-checker (13)
Generators optimize for demos: open data paths, client-trusted roles, missing rate limits, and secrets in env files that ship to browsers. On token-leak-checker, re-check those classes after every feature prompt. Search diffs for deleted middleware, new admin routes, and dependency adds. Reject ’temporarily disable auth’ comments without a tracking ticket and expiry.
# smoke verification sketch for token-leak-checker
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"
Verification commands and proofs (14)
Proof beats intention. For token-leak-checker, keep a script or checklist that demonstrates deny paths: anonymous access fails, user A cannot read user B, webhooks reject bad signatures, and bundles lack server secrets. Store the last run date next to the checklist. If the date is older than your release cadence, you are flying blind.
// deny-by-default sketch used near token-leak-checker
export function assertOwner(userId: string, ownerId: string) {
if (userId !== ownerId) throw new Error('forbidden');
}
CI and release gates (15)
Encode the minimum bar in CI so humans do not renegotiate under launch pressure: secret scan, dependency audit, unit tests including authz negatives, preview deploy, live security scan failing on criticals. For token-leak-checker-related paths, add CODEOWNERS so reviews land on people who understand the threat model.
Environment separation (16)
Production credentials must not appear in previews or local agent sandboxes. Separate projects or branches for data stores, separate OAuth redirect allowlists, and separate Stripe test vs live keys. Document the matrix where coding agents can read it so ‘make preview work’ does not copy prod secrets again.
# smoke verification sketch for token-leak-checker
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"
Logging, monitoring, and abuse (17)
Log authentication failures, authorization denials, and high-cost endpoints with request ids. Alert on spikes. Rate limit auth and AI proxy routes. For token-leak-checker, define what ‘abnormal’ looks like before an attacker teaches you under load.
Related tools and guides
- Vibe Code Scanner — full security scan of a deployed AI-generated app.
- Firebase Scanner — Firestore rules, auth, and storage bucket checks.
- Supabase RLS Checker — verify every table has a correct policy.
- Lovable Safety Guide — what Lovable ships insecure by default and how to fix it.
- Replit Safety Guide — common exposure patterns in Replit-deployed apps.
- OWASP Top 10 for AI Code — the canonical failure modes.
- Env Exposure Checker — related misconfiguration class.
- Source Map Checker — public maps that amplify leaks.
- How to Secure Vercel —
NEXT_PUBLIC_discipline.
COMMON QUESTIONS
KEYS CLEAN? TEST THE REST
Token leaks are critical — but open databases and broken auth sink apps too. Run the full agent on the same URL.
14-day free trial · No credit card · Cancel anytime