Everything here is general guidance, not professional advice. We research carefully and can still be wrong or out of date, so treat it as suggestions to check rather than instructions to follow, and accept that you act on it at your own risk. Full terms.

BlogAPI key leaked on GitHub, what to do

API key leaked on GitHub, what to do

Revoke the key at the company that issued it before you delete the commit. GitHub says a leaked secret is already compromised. Removing the file, pushing a new commit, or deleting the repository does not stop anyone who copied it.

An API key in a GitHub repository is leaked as soon as it is pushed, even if you delete the file a minute later. Revoke it at the company that issued it. Then point your app at a new key. GitHub’s remediation guide says you should treat any leaked secret as compromised immediately. Removing it from the code, pushing a new commit, or deleting and recreating the repository does not stop someone who already copied it.

The longer checklist is Production API key leaked. If the same commit contains customer records, not only a key, use Private data appears in a public repository after the key is dead. If you did not push the key, and the repository or the organization looks changed by someone else, use GitHub organization compromised.

Name the key and where it sits

Write down three things before you start clicking.

  1. What the secret is, and who issued it. A GitHub personal access token, a cloud key, a payment key, and an SSH private key are revoked in different places.
  2. The repository, the file, and the line.
  3. Who owns it. The CODEOWNERS file is one place to look. git log -S on a local clone shows the commit that introduced the string.

If secret scanning is on, the alert already has most of this. You need write access to the repository to do the cleanup. You do not need secret scanning to revoke the key.

Secret scanning is free for public repositories. For a private repository it is part of GitHub Secret Protection, on GitHub Team and GitHub Enterprise Cloud.

Decide how fast to cut it off

GitHub says public scanners can find an exposed secret in minutes, and that it can be used within hours. The longer an active key stays valid, the worse the outcome.

Treat it as high risk if any of these are true.

  • The alert says the secret is still active. Validity checks exist only for some secret types. The provider’s own page is the source of truth, not the label.
  • The alert has the label public exposure.
  • The key is a production credential.

The alert label multiple leaks means the same secret is in more than one place. A GitHub personal access token alert can also show when it was last used, and what scope it had.

For a high-risk key, revoke it now. If those minutes of downtime would take the product offline, GitHub says you can create a new secret with the same permissions, switch the app to it, and then revoke the old one. Tell the owner, the repository admins, and whoever leads security, during that work or straight after.

A key that is already inactive, that sat only in a private repository, or that was a test credential is lower risk. It still gets revoked. GitHub says a medium or low risk secret can still matter for security and for compliance. You can pick a moment with the team so the new key lands before the old one dies. You do not leave it in place.

A public repository is the dangerous case even when secret scanning is off. Look at whether the file is a deploy script or a test fixture, and whether the key is an admin credential. Then revoke.

Revoke it at the issuer

This is the step that matters. Find the provider’s site and open the page that lists API keys. Delete or revoke the leaked one. If you cannot sign in there, the person who created the key has to do it.

Create the replacement with the smallest permission the app needs. Put the new value in the same store the app already reads, such as the repository’s Actions secrets. Do not paste the new key into the file you are about to commit.

A few GitHub tokens are revoked for you.

  • GitHub’s token page says a valid OAuth token, GitHub App token, or personal access token pushed to a public repository or a public gist is revoked automatically. You cannot turn a revoked token back on. You create a new one.
  • The remediation guide says the same for GitHub personal access tokens in a public repository. In a private repository, open the secret scanning alert and click Report leak. That report is for active or unconfirmed GitHub personal access tokens.
  • If a public leak matches one of GitHub’s partner patterns, GitHub tells the provider, and the provider may revoke it. “May” is the word GitHub uses. Open the provider and check.

Delete a personal access token you still see, even if you expect the automatic revoke.

  1. Click your profile picture, then Settings.
  2. In the left sidebar, click Developer settings.
  3. Under Personal access tokens, click Fine-grained tokens or Tokens (classic).
  4. Next to the token, click Delete.

GitHub’s token management page documents that path. Deleting a token that created a deploy key deletes that deploy key too.

If you found someone else’s GitHub token, GitHub documents a revocation API for tokens that start with ghp_, github_pat_, gho_, ghu_, or ghr_. The token page points at that API. Do not paste the token into a chat or a ticket while you do it.

Find every other copy

A second copy in another repo, an issue, or a pull request is still live until you revoke, and it is a clue that the same key was reused.

GitHub’s guide says to search with code search.

  • Across an organization: org:YOUR-ORG "SECRET-STRING"
  • In one repository: repo:YOUR-REPO "SECRET-STRING"

Use a distinctive slice of the key. Keep the search inside your account. Do not paste the key into a public gist, a screenshot, or a support form if you can describe the last four characters instead.

Then, in the repository, click Settings. Under Security, open Secrets and variables, and open Deploy keys. Update the Actions secret so the next workflow uses the new key. Check GitHub Apps and other integrations that were handed the old value.

The old key has to fail a real request before you call this done. A new key that works, next to an old key that still works, is not a rotation.

See if it was used

When the app is on the new key, look for use of the old one.

On GitHub, that is the security log for a personal account, or the audit log for an organization or an enterprise. Organization and enterprise logs can be filtered to actions performed by an access token. You need the right role. An organization owner may have to pull the log for you.

At the provider, open the audit log for that key. GitHub’s example for Amazon Web Services is CloudTrail. Use whatever log the issuer gives you. Write down the time the key first hit the repository, and any call you do not recognise after that.

Save those logs before you delete the alert or rewrite history. The repository you are about to edit is a bad place to store the only copy.

Clean the git history only after the key is dead

The secret can still sit in old commits, forks, and pull requests after the file is gone from the latest version. GitHub’s removal guide says to revoke or rotate first. Once the secret no longer works, rewriting history may not be worth it.

Rewrite history when the text itself is still dangerous if someone reads the old commit. A password you could not rotate everywhere, or personal data in the same file, is that case. A cloud key you have already revoked is usually not.

A rewrite has sharp edges. GitHub lists them.

  • An old clone can put the secret back. Someone runs git pull and then git push, and the cleaned history is undone. They have to re-clone, or clean their clone on purpose.
  • Commit hashes change. Branch protection that blocks force pushes has to come off for the push, then go back on.
  • Open pull requests should be merged or closed first. Comments on the old diff can disappear.
  • Signed commits and tags lose their signatures.
  • Forks keep the old commit. GitHub cannot give you the fork owners’ contact details. You have to ask them to delete the fork or clean it.
  • Cached views and pull request copies can still serve the file by its old commit hash. GitHub Support will remove those only when they decide that rotating the credential is not enough. They will not remove data that is not sensitive.

If you do rewrite, GitHub’s current tool is git-filter-repo, at least version 2.47, because that version has --sensitive-data-removal. Work on a fresh clone. To drop one file from all history:

git-filter-repo --sensitive-data-removal --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA

The path is the path inside the repository, such as src/payments/client.ts. If the file was renamed, pass every old path, or run the command again. To replace the secret text instead of deleting the whole file, put the strings in a file outside the repo and run:

git-filter-repo --sensitive-data-removal --replace-text ../passwords.txt

Check the history before you push. GitHub says this push is the point of no return. Count the pull requests that will change with:

grep -c '^refs/pull/.*/head$' .git/filter-repo/changed-refs

Then:

git push --force --mirror origin

Refs under refs/pull/ will fail. GitHub marks them read-only. Any other failure is usually branch protection. Turn that protection off, push again, and turn it back on. After the push, contact GitHub Support with the owner and repository name, the number of affected pull requests, and the first changed commit that git-filter-repo printed. If the output says LFS objects were orphaned, say so and attach the file it names.

Colleagues rebase branches onto the new history. A merge from the old history can bring the secret back in one commit.

If the leak included customer data, revocation of a key does not undo that exposure. List what was in the file, who it describes, and get legal advice about notice. Rules depend on the country and on the kind of data. Private data appears in a public repository is the checklist for that half of the incident.

Close the alert and block the next push

If a secret scanning alert is open, close it as Revoked. Write down the provider, the time you revoked the key, and what the logs showed. Keep that note outside the repository.

Stop the next accident with the control that matches your plan.

Push protection for your own account blocks pushes of supported secrets to any public repository.

  1. Click your profile picture, then Settings.
  2. In the Security section of the sidebar, click Code security.
  3. Under User, next to Push protection for yourself, turn it on.

GitHub’s user push-protection page is that path.

Repository push protection blocks contributors, and it alerts you if someone bypasses it. It is part of GitHub Secret Protection. The enable page says:

  1. Open the repository and click Settings.
  2. In Security and quality, click Advanced Security.
  3. If Secret Protection is off, click Enable next to it.
  4. Next to Push protection, click Enable.

Keep new secrets out of the repository. GitHub’s removal guide names environment variables, and secret managers such as the repository’s Secrets and variables store, Azure Key Vault, AWS Secrets Manager, or HashiCorp Vault. A pre-commit check such as gitleaks catches a key on your machine. Push protection catches it at GitHub. Neither one revokes a key that is already public. That part stays the provider’s revoke button.

If the leak came with a new owner, a new app, or a private repository that flipped to public, the key is only the first credential. Continue with GitHub organization compromised. If the key is dead and the app is on the new one, finish the prepare list in Production API key leaked.

Questions

I pushed an API key to GitHub. What do I do first?

Revoke it at the provider that issued it. GitHub says any leaked secret should be treated as compromised immediately. Deleting the file, pushing a fixup commit, or deleting the repository does not stop the key from being used. If the key is still active, public, or used in production, revoke it now. If a few minutes of downtime is the problem, create a new key with the same permissions, point the app at it, and then revoke the old one.

Does GitHub revoke the key for me?

Sometimes. A valid personal access token, OAuth token, or GitHub App token pushed to a public repository or a public gist is revoked automatically. For a GitHub personal access token in a private repository, open the secret scanning alert and click Report leak. For other providers, GitHub reports a public leak when the key matches a partner pattern, and that provider may revoke it. Confirm the old key fails at the provider. Do not assume the partner already did it.

Should I rewrite git history?

Only after the key is revoked, and only if the secret text still has to disappear. GitHub says that once a secret is revoked, rewriting history may not be needed. A rewrite changes commit hashes, needs a force push, and an old clone can push the secret back. GitHub Support removes cached copies only when rotating the credential is not enough to remove the risk.

The repository was private. Is the key safe?

Treat it as leaked. Secret scanning on a private repository needs GitHub Secret Protection, on GitHub Team or GitHub Enterprise Cloud. A private leak is a smaller audience than a public one, and it is still a key you no longer control. Revoke it, then search the rest of the organization for the same string.

How do I stop the next push?

Turn on push protection for yourself. On GitHub, click your profile picture, Settings, Code security, and switch on Push protection for yourself. That blocks you from pushing supported secrets to a public repository. Repository push protection is part of GitHub Secret Protection. Secret scanning itself is free on public repositories.