You Pushed Your API Key to GitHub — Now What?
You just pushed an API key to GitHub. Here's what happens in the next 60 seconds, and the exact steps to take before the damage spreads. Move fast.
Rod
Founder & Developer
You just pushed an api key to GitHub and you know it. Your stomach dropped. Here's what you need to know: bots are already looking. GitGuardian's research shows the average time from a secret being pushed to a public repo to first unauthorized use is under 4 minutes.
Stop reading the intro. Here's what to do right now.
Step 1 — Revoke the Key. Before Anything Else.
Do not clean the git history first. Do not make the repo private first. Revoke the key.
Every second the key is valid, it can be used. An attacker who scraped it 30 seconds ago is holding live credentials. The only thing that stops ongoing damage is invalidating those credentials at the source.
Go to the provider's dashboard and invalidate the compromised key:
- Stripe: dashboard.stripe.com/apikeys — click the key, hit "Reveal", then "Roll key"
- OpenAI: platform.openai.com/api-keys — "Revoke" next to the key
- AWS: IAM console — Deactivate the access key, then delete it
- Supabase: Project Settings > API — regenerate the service role key
- Twilio: Console > API Keys — revoke the specific key
- GitHub: Developer Settings > Personal Access Tokens — revoke it
Generate a new key immediately after revoking. Don't wait. You need a replacement ready before you fix the code.
Step 2 — Check If It Was Already Used
Before you declare the incident closed, check whether the key was used after it was compromised.
Most providers have an API usage log or audit trail:
# AWS: Check CloudTrail for activity after the push timestamp
# Look for calls you didn't make
# Stripe: Dashboard > Developers > Logs
# Filter by the date/time of the push
# OpenAI: Usage dashboard
# Compare usage against what you expectLook for requests from IP addresses you don't recognize, at times you weren't working. If you see suspicious activity, the incident is bigger than a leaked key — you may need to audit what the attacker accessed with it.
Step 3 — Make the Repo Private (If Public)
This doesn't fix the problem, but it stops new exposure to bots actively scanning GitHub's public event stream.
Go to your repo settings > Danger Zone > Change repository visibility > Make private.
If the repo is already private, skip this step. Private repos are still scanned by GitHub's own secret scanning feature, but they're not indexed by third-party scrapers.
Step 4 — Move the Key to an Environment Variable
Before you generate the new key and put it back in your code, fix the code that caused this:
# BAD: The pattern that got you here
const client = new SomeService("sk_live_actualKeyHere");# GOOD: Environment variable — the key never touches your source code
const client = new SomeService(process.env.SERVICE_API_KEY);Add the variable name to your .env.example file (with a blank value). Make sure .env and .env.local are in your .gitignore.
# .gitignore — these lines must be there
.env
.env.local
.env.production
.env*.localCheck your .gitignore exists and has these entries before you commit anything else.
Step 5 — Clean the Git History
The key is still in your git history. Anyone who clones your repo (including anyone who cloned it before you made it private) can find it with:
git log -p | grep "your_key_prefix"You need to rewrite history to remove it. Two tools do this:
Option A — git filter-repo (recommended)
# Install git-filter-repo
pip install git-filter-repo
# Remove the file that contained the key from all history
git filter-repo --path path/to/file/with/key.ts --invert-paths
# Force push to remote
git push origin --force --allOption B — BFG Repo Cleaner (simpler for single files)
# Download BFG from rtyley.github.io/bfg-repo-cleaner/
# Then replace the literal secret string in all history
java -jar bfg.jar --replace-text secrets.txt
git push origin --force --allAfter force-pushing, GitHub may cache the old commits for a short period. Contact GitHub support to expedite the cache purge if you need it cleaned immediately.
Step 6 — Check the Rest of Your Repo
You found one leaked key. That doesn't mean it's the only one.
When we scan repos that come in for incident review, we find an average of 3-5 additional secrets alongside the one the developer already knew about — often in older files, config files, or test fixtures.
Scan your full repo for secrets free →
Data Hogo's scan checks for API keys, tokens, credentials, and connection strings across all files in your repo using Gitleaks + regex patterns. Takes under 5 minutes. Worth doing now while you're already in incident mode.
For the full remediation walkthrough — not just the panic steps but the thorough cleanup — read the complete guide to fixing an exposed API key on GitHub. That guide covers git history rewriting in more depth, rotating credentials across services, and preventing the next incident.
Why Deleting the File Doesn't Help
Worth being explicit: if you tried to fix this by deleting the file containing the key and committing the deletion, the key is still there.
# This does NOT remove the key from history
git rm config.js
git commit -m "remove api key"
git pushGit stores every version of every file ever committed. The deletion commit hides the file from the current state of the repo but anyone running git log -p or git show <commit-hash> can see the key in previous commits.
The only fix is the git history rewrite in Step 5.
How to Not Be Here Again
Three things prevent this:
1. .env files for all secrets
Every credential goes in a .env file. The .env file goes in .gitignore. Your code reads from process.env, never from literal strings. This is non-negotiable.
2. Pre-commit hook with Gitleaks
# Install gitleaks
brew install gitleaks
# Add to .git/hooks/pre-commit
gitleaks protect --staged --redactThis scans your staged changes before every commit and blocks the commit if it finds a secret. You literally can't push a key this way.
3. Periodic repo scans
Pre-commit hooks catch new secrets. They don't catch secrets that were already there before you set up the hook. A full repo scan periodically finds what you might have missed.
The env file security guide covers the .env setup in detail, including what to do when you accidentally commit an entire .env file.
Frequently Asked Questions
How fast do bots find API keys pushed to GitHub?
Very fast. GitGuardian's research shows an average of under 4 minutes from a secret being pushed to a public GitHub repo to first unauthorized use. Automated scrapers run continuously against GitHub's public event stream. Treat any push to a public repo as immediately compromised.
Does deleting the commit remove the API key from GitHub?
No. Git history is permanent. Even if you delete the file and make a new commit, the secret is still in your git history and visible to anyone who clones the repo. You must revoke the key AND clean the git history to fully remediate.
What should I do first when I leak an API key on GitHub?
Revoke the key immediately — before anything else. Go to the service provider's dashboard and invalidate the compromised key. Then generate a new key, move it to an environment variable, and clean the git history. Revocation is the only action that stops ongoing damage.
Can I make a private repo to fix a leaked API key?
Making the repo private helps stop new exposure but doesn't fix the problem. The key is already in your git history. Anyone who cloned the repo before you made it private still has it. You still need to revoke the key and clean the history.
How do I prevent pushing API keys to GitHub in the future?
Use environment variables and a .env file that's listed in .gitignore. Add a pre-commit hook that scans for secrets before any commit goes through. Run periodic repo scans with a tool like Data Hogo to catch anything that slips through.
The incident isn't over when you stop panicking. It's over when the old key is revoked, the new key is in an environment variable, the history is clean, and you've checked for other secrets you might have missed.