Why Deleting a Leaked API Key From Git Is Not Enough
Security Intermediate 4 min read

Why Deleting a Leaked API Key From Git Is Not Enough

A leaked API key keeps working until the issuer revokes it. Why force-pushing it out of Git fails, and how to revoke, verify and scope the blast radius.

Published: October 25, 2026 • Updated: October 25, 2026
secrets managementapi keysincident responsegit

A leaked API key stays dangerous until the system that issued it stops accepting it. Deleting the commit, force-pushing over it or making the repository private does not do that. In the LiteLLM case, a master key committed to a public repository on 27 May 2026 was force-pushed over and flagged for revocation, but never revoked. An attacker used it 136 days later to start the chain that ended in a malicious release on PyPI.

Why is deleting a leaked API key from Git not enough?

Removing a secret from Git only changes what the repository shows today. Anyone who cloned, forked or cached the repository while the secret was visible may still have a copy, and the key itself keeps working until it is revoked at the source.

Public repositories are scanned continuously by automated tools looking for credentials, so the safe assumption is that a key was copied within minutes of the push. A force-push hides the evidence from casual readers. It does not reach copies that already left.

What does revoking a leaked API key actually involve?

Revoking a leaked API key means invalidating it in the issuing system, issuing a replacement, deploying the replacement everywhere the old one was used, and confirming the old one now fails. Until the last step is checked, the work is not done.

Each step has a common failure:

  1. Invalidate at the issuer. Disable or delete the key in the provider console or identity system, not just in your config. LiteLLM's master key was flagged for revocation, and that flag never turned into the actual action.
  2. Issue and deploy a replacement. Find every consumer first. Keys copied into CI variables, laptops and secondary services are the ones that keep the old value alive or break production when you cut over.
  3. Verify the old key fails. Make a test call with the old key and confirm it is rejected. A ticket marked done is not evidence.
  4. Review what the key did while exposed. Pull the issuer's access logs for the whole exposure window, not just the last day.

Follow the blast radius, not just the key

The LiteLLM chain shows why the review in step 4 matters. LiteLLM's root cause analysis says the attacker used the master key on 10 October against the Agent Platform API, and one response returned a GitHub CLI OAuth token belonging to an organization owner. That token had owner-level access across the organization, so the attacker could run workflows that sent repository secrets out, including two maintainer tokens. Those tokens then approved a release.

So the question after a leak is not only "is this key revoked?" It is "what could this key reach, and what secrets live behind it?" For each leaked credential, list:

  • Data and APIs the credential can read directly.
  • Other credentials stored where it can reach, such as tokens kept by a platform, secrets in CI, or keys in a database.
  • Systems that trust it implicitly, such as release pipelines and deployment approvals.

Anything on that list that was readable during the exposure window needs its own rotation. Our earlier guide on how to rotate every secret a file-read bug could have exposed walks through building that inventory.

How do you stop a revocation from getting lost?

You stop it by making revocation a tracked incident task with a named owner and a verification step, not a note in a chat thread. Treat any secret pushed to a public repository as a security incident, even if it was removed within seconds.

Practical controls that close the gap seen in the LiteLLM case:

  • Turn on secret scanning with push protection for your source hosting, so most leaks are blocked before they become public.
  • Make revocation the first step of the response playbook, before history cleanup. Cleaning history is cosmetic; revocation is the fix.
  • Prefer short-lived credentials. A key that expires in hours cannot sit unused for 136 days.
  • Scope tokens narrowly. The GitHub OAuth token in this chain had no scope restriction and owner-level access. A token limited to one repository and read access would have stopped the chain early.
  • Audit long-lived keys on a schedule. Review every key older than a set age and confirm it still has an owner and a reason.

What to do if you find an old leak today

If you find a key that was exposed months ago and never revoked, assume it was used. Revoke it now, then pull the issuer's logs for the full period and look for access from unfamiliar addresses. Rotate anything the key could reach. If logs show use, treat it as a breach and follow why you should rebuild before you rotate credentials.

The full timeline of the incident that prompted this guide is in our report on the LiteLLM supply chain attack and the 1.107.0 release. To keep the next poisoned package out of your own builds, see how to pin Python dependencies with pip hash checking.