API keys leaked on GitHub: how to find them and what to do

Why passwords and keys end up in public repositories, how attackers find them within minutes, and the order to act in: revoke first, clean the history second.

7 min read

A developer copies a working .env file into a test project, pushes it to a public repository “for a minute”, and deletes it the same afternoon. The database password, the payment key and the SMTP credentials of your company are now public, and they stay public: in the repository’s history, in every fork, and in the archives of the bots that read GitHub’s public stream continuously.

This is one of the most common ways small companies are breached, and one of the cheapest to prevent.

How secrets end up in public code

  • Configuration files committed by mistake: .env, config.yml, settings.py, wp-config.php, appsettings.json.
  • Personal or freelance repositories: a contractor publishes a portfolio project built for you, with your real credentials inside.
  • Deleted in the next commit: the file is gone from the current version, but anyone can read the previous commit.
  • Test scripts and notebooks: a quick script to send an e-mail, with the SMTP password written in it.
  • Connection strings: postgres://app:password@db.yourdomain.com/app, which give away both the password and where to use it.

How fast they are found

Automated scanners watch every public push. Studies of leaked cloud keys regularly show them being tried within minutes. GitHub’s own secret scanning now checks public repositories for the keys of hundreds of providers and warns some of those providers, who may revoke the key; it does not cover database passwords, SMTP accounts or your own internal tokens.

Search for your own domain

Attackers search for your company by its domain name, because configuration files name the servers they connect to. You can do the same. On GitHub, search code for:

"yourdomain.com" password
"yourdomain.com" secret
"yourdomain.com" filename:.env

Look at every result outside your own organisation. A file that names your domain next to password= or a key is worth opening.

What to do when you find one: revoke first

The order matters, and most people get it backwards.

  1. Revoke or change the secret immediately. Generate a new key, change the password, rotate the token, in the service it belongs to. Until you have done this, nothing else counts: deleting the file does not make the old secret secret again.
  2. Check whether it was used. Look at the logs of the service: sign-ins, API calls, mail sent, new users, unexpected invoices, from the date of the commit.
  3. Remove it from the code. If the repository is yours, rewrite its history with git filter-repo (GitHub documents this as “removing sensitive data from a repository”) and ask GitHub support to purge cached views. If it belongs to someone else, ask the owner to remove it; for a person who does not answer, GitHub accepts requests to remove sensitive data from repositories you do not own.
  4. Find out how it happened and stop the next one: a .gitignore for environment files, secret scanning with push protection on your own repositories, and secrets kept in a manager rather than in files.

Preventing the next leak

  • Keep secrets out of code entirely: environment variables injected at deploy time, or a secret manager.
  • Turn on GitHub’s push protection for your organisation’s repositories: it blocks a push that contains a recognised key.
  • Run a scanner such as gitleaks in your CI, so a secret fails the build before it is merged.
  • Give contractors their own credentials, with limited rights, and revoke them when the work ends.
  • Prefer keys restricted to what they need: one domain, one IP range, read-only where possible.

How Perimetry watches for you

Every week, Perimetry Cloud searches public code on GitHub for files that mention your proved domains, reads them, and recognises passwords and keys: AWS, Stripe, GitHub, GitLab, Slack, SendGrid, OpenAI and Anthropic keys, private keys, passwords in connection strings and configuration next to your domain. It never keeps the secret itself, only its type, its first characters and where it is, and it alerts you when a new serious one appears. The same audit also looks at the files the Internet Archive kept from your sites (old backups and configuration files), which leak the same way.