I Accidentally Pushed My API Keys to GitHub, How Bad Is It?
6 min read
You pushed your .env file, or a config file with secret keys in it, to a
GitHub repo. The direct answer: treat every key in that file as compromised
and rotate it now. A secret that has been public, even for a minute, even in a
repo you have since made private, has to be replaced. Deleting the file does not
undo the exposure. Rotating the key does.
Why this happens
Your AI agent wrote code that reads keys from a .env file, which is correct.
What it often skipped is adding .env to .gitignore, so when you ran
git add . and pushed, the secrets went up with everything else. The agent
built the part you asked for, the working feature, and stayed quiet about the
file you didn't know to exclude.
The reason this is serious is that GitHub is scanned constantly. Bots watch new public commits for anything shaped like a key and try it within seconds. An exposed OpenAI, Stripe, or database key can be running up a bill or reading your data before you have finished reading this sentence. "It was only up for a few minutes" is not a defence, because the minutes are all the bots need.
How to check
-
Look at what is actually tracked in git. In your project folder:
git ls-files | grep -E "\.env|secret|credential"Anything that prints here is committed. It is in your history whether or not it is still in your latest version.
-
Search your whole history, not just the current files:
git log --all --full-history -- .envIf that returns any commits, the file lived in your repo at some point and the keys inside it are exposed.
-
Check GitHub itself. Open your repo on github.com and look at the Security tab. If secret scanning has flagged anything, GitHub already found a key, and so did everyone else watching.
The fix
-
Rotate every exposed key first. This is the only step that actually closes the hole. Regenerate each secret in the provider's dashboard: Stripe, OpenAI, Supabase (service role), your database URL, any third-party API. The old key stops working, so anyone holding a copy is locked out.
-
Update your local
.envwith the new keys and, if you deploy on Vercel, Netlify, or similar, update the environment variables there too. Redeploy so production picks up the new values. -
Stop tracking the file. Add it to
.gitignore, then remove it from tracking without deleting your local copy:echo ".env" >> .gitignore git rm --cached .env git commit -m "Stop tracking .env" git push -
Confirm it is gone from the working tree with
git ls-files | grep env, which should now print nothing.
The trap to avoid
The tempting wrong fix is to delete the file, or git rm it, and push a commit
that "removes" the secrets. It does not remove them. The old commit still sits in
your history, and anyone can browse to it or clone the repo and read the keys.
People also make the repo private and stop there, assuming that hides it. The
key was already scraped while it was public. Rewriting history is optional
cleanup; rotating the keys is the fix. If you never rotate, you are exposed no
matter how tidy the repo looks.
Where this fits
A leaked secret is one of the fastest ways a vibe-coded app gets abused before it has a single real user, and it is easy to miss because nothing in your app looks broken. The free Readiness Report scans your project for committed secrets and tells you which keys need rotating, in priority order. If you would rather have the fixes done for you, that is the Finishing Pass. Once your keys are safe, the next thing worth understanding is which keys are actually meant to be public: see what the anon key is and whether it's safe to expose, and whether a stranger can read your database from the browser.