KeyDrift
Free scan

KeyDrift

Every way a secret ends up in a browser

A client bundle is supposed to contain some credentials. The failures worth losing sleep over are the others: keys that must never reach a browser but do — created at build time, written by an agent chasing a working call, or pasted wherever the demo looked best.

Each page below explains one situation precisely, gives the fix in the same breath as the finding, and finishes with the same offer: fetch your deployment and look.

The failures on this hub share one shape. Nothing throws. The build passes, the deploy succeeds, the smoke test is green, and the key sits in a file that every visitor's browser downloads. By the time anyone thinks to look — usually because an OpenAI bill spikes or a Stripe dashboard shows activity nobody recognises — the string has been public for weeks.

Three forces produce almost every page listed here.

Build-time substitution. Environment prefixes look like configuration and behave like publication. NEXT_PUBLIC_ and VITE_ are instructions to the bundler: take this literal value and write it into the output. The repository never changes; the .env file stays ignored; the leak exists only in the artifact those tools produce. A scanner that reads source reads the wrong file.

Agent imitation. AI coding tools reach for the shortest path that makes the query return rows. Ask for a Supabase call in a Lovable app and the working version holds the service_role JWT, because the SPA has no server to hold anything. Fix one file and the pattern remains in the codebase's gravity; the next feature request reproduces it. This is why regression matters more than discovery — the comeback, not the first appearance, is where monitoring earns its keep.

Credential illiteracy under deadline. An sk_live_ key and a pk_live_ key differ by one letter and by everything. Teams under pressure paste whichever one made the demo work. Part of what KeyDrift does is boring taxonomy: recognising that anon keys, publishable keys and Firebase web keys belong in browsers, so that a service_role JWT beside them gets reported as the emergency it is — and never the reverse.

How to use this section. If you know the tool your app was built with, start in the first group: each page traces one tool's specific mechanics from prompt to served chunk. If you know the build system instead — Next.js, Vite, Nuxt, Remix — the second group explains exactly where substitution happens and what survives it. If you found a string and want to know what it is, the third group covers every provider KeyDrift detects, including the ones that are supposed to be public. And if you already know the worst — a key is live, someone else may have it — skip to the incident group and follow the runbooks in order. Rotation comes before investigation, always.

Two honest boundaries apply everywhere below. These scans see deployed web artifacts only: no mobile binaries, no private networks, no repositories, and nothing behind a login except through paste mode. And detection is pattern plus entropy plus context, not a JavaScript parser — a key assembled at runtime from fragments is outside every bundle scanner's honest reach, ours included.

Secrets left behind by AI coding tools

Lovable, Bolt, Cursor, Claude Code, Replit and friends optimise for “it works” — sometimes the working version holds a live key.

How builds move secrets into bundles

NEXT_PUBLIC_, VITE_, hydration payloads, source maps, preview deploys: substitution happens after review, alone.

Credentials by provider

What each key grants, how it travels into a bundle, whether it belongs there, and how to rotate it.

Found a leaked key

Runbooks in response order: rotate first, audit usage, fix the source, verify the deploy.

Straight answers

Symptom-first pages for the questions people actually type at an assistant.

Run one check now

Every page on this hub ends the same way, because there is only one honest way to know what a deployment serves: fetch it and look. The scan is free, needs no account, and takes about as long as reading this sentence.

No account. Read-only — the scanner only ever issues GET requests, and never stores a key: findings carry a masked prefix and a fingerprint.

KeyDrift · free URL or paste-source scan