HomeProjectsBlogContact

Leaked an API Key on GitHub? Do This in the Next 10 Minutes

Bots scan public repositories for secrets constantly. If you pushed a key, deleting it isn't enough. The exact order of steps: revoke, check for damage, clean history, and prevent a repeat.

Leaked an API Key on GitHub? Do This in the Next 10 Minutes

It happens to experienced developers too. A quick test, a .env that wasn't in .gitignore, a config file you forgot contained a token, and suddenly a secret is sitting in a public repository. Don't panic, but do move quickly. Automated scanners crawl public commits constantly, and leaked cloud keys can be abused within minutes.

Here's what to do, in order.

Step 1: revoke or rotate the key immediately

This is the only step that actually stops an attacker. Everything else is cleanup.

  • Go to the provider's dashboard (cloud provider, payment processor, AI API, email service, database host).
  • Revoke or delete the leaked key, then create a new one.
  • Update the new key wherever your app runs: hosting environment variables, CI secrets, your local .env.

Do this before rewriting Git history. Deleting the commit doesn't help if someone already copied the key, and you have to assume someone did.

If the leak included a database connection string, change the database password. If it was an SSH key, remove it from every server's authorized_keys.

Step 2: check for damage

Look for signs the key was used by someone else:

  • Usage and billing dashboards. Unexpected spikes in API calls, compute instances you didn't create, unfamiliar regions.
  • Audit logs. Cloud providers log API activity. Filter by the leaked key.
  • Your data. For database credentials, check for unexpected tables, dropped data or new users.
  • Email/SMS services. Look for messages you didn't send. Leaked messaging keys are popular for spam.

If you find abuse, contact the provider's support. Many will help with unexpected charges, especially when you act fast and have already rotated the key. Turn on billing alerts and spending caps while you're in there.

Step 3: remove the secret from Git history

A new commit that deletes the key leaves it in history, readable by anyone who browses old commits. To really remove it, rewrite history.

The recommended tool is git filter-repo:

# Replace the secret text everywhere in history
echo 'sk_live_LEAKED_VALUE==>REMOVED' > replacements.txt
git filter-repo --replace-text replacements.txt

# Or remove a file from all history
git filter-repo --invert-paths --path .env

BFG Repo-Cleaner is a popular, simpler alternative for the same job.

Then force push the cleaned history:

git push --force-with-lease --all
git push --force-with-lease --tags

Know the limits:

  • Anyone who already cloned or forked the repo still has the old history.
  • Hosted platforms may keep cached views of old commits for a while. GitHub's documentation explains how to request removal of cached data.
  • Teammates need to re-clone, or they may push the old history back.

That's exactly why Step 1 comes first. Rewriting history is hygiene, not a fix.

Step 4: find out how it happened

  • Was .env missing from .gitignore?
  • Was the key hardcoded "just for testing"?
  • Did a log file, build output or config dump get committed?
  • Was it in a notebook output, a screenshot, a Docker image layer?

Fix that root cause, or it'll happen again.

Step 5: prevent it next time

Ignore secret files from the start:

.env
.env.*
!.env.example
*.pem
*.key

Scan before commits reach the server. Tools like gitleaks or detect-secrets can run as a pre-commit hook and block a commit that contains something that looks like a key.

Turn on platform protection. GitHub offers secret scanning and push protection, which blocks pushes containing known secret formats. Many providers also partner with GitHub to automatically revoke their keys when they appear in public repos. That's helpful, but don't rely on it.

Use least privilege. A key that can only read one bucket does far less damage than an admin key. Create scoped keys per app and per environment.

Keep secrets in environment variables or a secret manager, never in code. (Here's a guide to doing that properly.)

Special cases

  • Frontend "public" keys (Supabase anon key, Firebase config, Maps keys restricted by domain) are designed to be visible. They're safe only if access rules are correct. Check your row-level security or security rules, and restrict keys by domain where possible.
  • Private repos aren't a safe place for secrets either. Treat a leak there seriously, just with less urgency.
  • Leaked in a screenshot or a stream? Same procedure: rotate first.

Quick checklist

  1. Revoke and rotate the key.
  2. Update the new key everywhere it's used.
  3. Check usage, billing and audit logs for abuse.
  4. Rewrite Git history and force push.
  5. Ask collaborators to re-clone.
  6. Add ignore rules, pre-commit scanning and push protection.

For the bigger picture, run through this web application security checklist.

FAQ

If I delete the commit, is my key safe?

No. Assume it was copied as soon as it was pushed. Revoke and rotate the key first. Cleaning the history comes second.

How fast are leaked keys exploited?

Often within minutes for public repositories, because automated tools continuously scan new commits for credential patterns.

Is it safe to make a repo public after removing secrets?

Only after the secrets have been rotated and removed from the entire history. A secret scanner like gitleaks can check the whole history before you flip the switch.

Keep reading

More from the workbench

All articles →