Your API key leaked. Here's what to do right now.
The short answer
Revoke or regenerate the key at the provider, right now, before you touch your code or your git history. That single action turns a live, usable credential into a dead string of characters, and it takes less time than reading this sentence twice. After that, in this order: check the provider’s usage or billing dashboard for anything that ran on your key while it was exposed; search your codebase and git history for other keys sitting nearby; clean up your git history if the key is buried in old commits; and tell someone if the key touched real customer data. Panic tends to make people scrub files first, but that’s backwards: a key sitting in fifty old commits isn’t dangerous once it’s dead at the source.
Step 1: Revoke or regenerate the key at the provider
This is the one action that matters more than everything else on this page combined, and it happens on the provider’s website, not in your editor. Every major provider has a page for this:
- OpenAI: your account’s API keys page, revoke the exposed one and create a new one.
- Stripe: the API keys section of the dashboard, “rotate” the key, old and new both work for up to 7 days so nothing breaks mid-deploy.
- AWS: IAM, find the user, deactivate the access key pair immediately, delete it once you’ve confirmed nothing still depends on it.
- GitHub personal access tokens: your developer settings, delete it directly.
Think of it like canceling a lost credit card. You don’t need to track down every place the number got written down. Once the card is dead, the number floating around stops being a threat. A revoked API key works the same way: it doesn’t matter how many old commits, chat logs, or screenshots still contain the string. None of them can do anything with it anymore.
If your leak happened in a public GitHub repo, there’s a decent chance GitHub already flagged it. GitHub runs secret scanning automatically and for free on public repositories, and for a number of providers, it notifies them directly so they can act on their end. That’s a useful backstop, not a reason to wait and see if it worked. Revoke it yourself regardless.
Once the new key exists, this is also the moment to put it where it belongs: an environment variable your app reads at runtime, and whatever secrets panel your hosting provider offers for production, never a value typed directly into a file that gets committed.
Step 2: Check the usage and the bill
Revoking the key stops what happens next. It does nothing about what already happened while the key was live and exposed. Open the provider’s usage or billing page and look at the window between when the key leaked and when you revoked it.
You’re looking for three things: a spike in request volume you didn’t generate, calls from places you’ve never touched, and charges that don’t match your own usage. Most providers keep at least some history of recent requests, so even if you catch a leak a few days late, the evidence is usually still sitting there. If you do find unauthorized activity, contact the provider’s support. This is a situation they see regularly, not an embarrassing confession, and they’re often better positioned than you are to tell what actually happened on their end.
While you’re in there, turn on a spending limit or usage alert if the provider offers one. It won’t stop a key from leaking again, but it puts a ceiling on how expensive the next mistake gets.
Step 3: Search your code and git history for other keys
A leaked key is rarely traveling alone. If one secret ended up hardcoded in a file instead of an environment variable, there’s a good chance others did too, from the same rushed commit or the same copy-pasted config file.
Search your whole project, not just the file where you found this one. Look for the actual prefixes providers use (sk- for OpenAI, AKIA for an AWS access key, sk_live_ for Stripe), across every file, including ones your editor hides by default. Check your git history too, not just the current state of the repo: a key removed from the latest commit can still sit untouched in an earlier one. Check any other project that reuses the same credentials too. This is a common way one leak quietly turns into three.
If your project’s .gitignore never listed .env, or only started listing it after the fact, fix that now as part of this same pass rather than a someday task.
Step 4: Clean up your git history if it needs it
Deleting a secret from your latest commit doesn’t remove it from your project’s history. Git keeps every version of every file it has tracked, and someone can dig an old value back out with a couple of commands. Once you’ve revoked the key in step 1, this stops being an emergency: a dead key sitting in an old commit can’t authenticate anything. But it’s still worth cleaning up properly, especially on a repo other people can see.
This is one of the more delicate corners of git to get right. Rewriting history changes the identity of every commit after the one you’re fixing, so anyone else with a local copy of the repo can end up out of sync, and you can’t reach or force-push over copies sitting in forks. GitHub’s own guidance points people toward a purpose-built tool, git filter-repo, for this rather than editing history by hand, because it’s easy to clean the wrong commit and leave the secret sitting in a different one than you meant to fix. If your repo has other collaborators or any public forks, this is worth doing carefully, ideally with someone who’s done it before, rather than as a first solo attempt on a repo you can’t easily restore if it goes sideways.
Step 5: Tell someone if customer data was involved
If the key only ever touched your own test data or a project nobody else depends on, you can stop once steps 1 through 4 are done. But if it was a database key, a payment key, or anything that could reach real people’s information, the calculus changes.
Figure out what the key could actually reach, not just what it did reach. A key with broad read access to a whole customer table is a bigger deal than one scoped narrowly. That’s part of why providers push people toward least-privilege keys in the first place, and it’s the kind of gap a missing row-level security policy often leaves open. Be honest with yourself about whether step 2 turned up actual evidence of misuse, or just exposure with no sign anyone used it. The two call for different responses. If customer data is actually at risk, that usually means telling the people affected, and depending on where your users are and what kind of data was involved, it may carry legal notification obligations. That last part is a question for a lawyer or your platform’s terms of service, not something to guess your way through on a stressful afternoon.
What Glim would tell you
None of this is fun to do alone, cycling through five dashboards trying to remember which one has the revoke button. Glimfly builds Glim, a firefly that sits next to your coding agent and narrates what it’s doing while it works, so you catch a key getting hardcoded into a file or printed to a log in the moment, not weeks later while writing a post like this one. Look up exposed API keys in the dictionary for the shorter version of why this happens in the first place.
People also ask
“How do I know if someone actually used my leaked API key before I revoked it?”
Check the usage or billing dashboard the provider gives you. Most show a log of recent requests with timestamps, regions, and cost per call. Look for anything you didn't run yourself: a burst of requests at an odd hour, calls from a place you've never deployed to, or spend that jumps past your normal pattern. If nothing looks unusual, you likely caught it before anyone used it.
“Is deleting the key from my code enough, or do I actually need to rotate it?”
Deleting it from your code does nothing to the key itself. It's still a live, working credential until you revoke or rotate it inside the provider's dashboard. It doesn't matter who copied that string before you deleted it, a bot scanning GitHub, a scraper, someone's screenshot: all of them can keep using it either way. Revoking first, cleaning your code second, is the order that stops the damage.
“Do I need to rewrite my git history if I already revoked the key?”
Not urgently. Once a key is revoked at the provider, the string sitting in an old commit is dead. It can't authenticate anything, so it stops being a security emergency the moment you finish that step. It's still worth cleaning out when you have a calmer afternoon, partly for hygiene and partly because a leaked key rarely travels alone, but it doesn't carry the same urgency as the revoke itself.
Words from this guide
Your API key is exposed: what happens, what to do, how to prevent it
An exposed API key is a secret that leaked somewhere public, and from that moment it works for whoever finds it, not just you.
securityAPI key vs secret vs token: what is the difference?
A secret is any credential you keep hidden; an API key is a long-lived secret identifying your app, and a token is a short-lived secret identifying a user or session.
filesWhat is an environment variable? (and why your app has a .env file)
An environment variable is a named value your app reads from its surroundings at runtime, instead of having it hardcoded, so secrets and settings can change without touching a line of code.
filesWhat is .gitignore? (the list of things git pretends not to see)
A .gitignore file is a plain-text list of file and folder patterns that tells git which things to never track, stage, or commit, even when they sit right there in your project folder.
Want this explained about your own project?
Glim watches your coding agent work and explains your sessions in plain words, live. Join the waitlist to get it first.