← All posts
·8 min read

Found Exposed API Keys in Your App? Here's What to Do Right Now

Your API key is in your source code, your git history, or your page source. Here is the exact step-by-step process to contain the damage and secure your app before more harm is done.

Stop. If you just found an exposed API key in your app — in your page source, your git history, a public GitHub repo, or a security scan — you need to act fast.

This is a time-sensitive situation. Every minute the key is active and exposed, someone could be using it to rack up charges on your account, access your users' data, send spam from your email service, or do worse.

Here's exactly what to do, in order.


Step 1: Revoke the key immediately (do this now, before reading the rest)

Before anything else, revoke the exposed key. This is your emergency brake.

OpenAI: Go to platform.openai.com/api-keys → find the key → click Delete.

Stripe: Go to dashboard.stripe.com/apikeys → Roll the key (creates a new one while deactivating the old one).

Supabase: Go to your Supabase project → Settings → API → click "Reset" next to the exposed key.

SendGrid: Go to Settings → API Keys → click Actions → Delete.

AWS: Go to IAM → Users → Security Credentials → Deactivate the access key.

GitHub Personal Access Token: Go to Settings → Developer Settings → Personal access tokens → Delete.

Twilio: Go to Console → Account → API Keys → Revoke.

For any other service: log in, find the API keys section (usually in Account Settings or Developer Settings), and immediately revoke or rotate the exposed key.

Do this before continuing. It takes two minutes and stops the bleeding.


Step 2: Create a new key to replace it

After revoking, create a fresh key for the same service. You'll need it once your app is fixed.

While you're creating it, apply the principle of least privilege: if the service offers key scopes or permissions, only grant what your app actually needs. A key that can only send emails should not also be able to manage billing.

Keep the new key somewhere safe (a password manager, or your deployment platform's secrets management) while you do the rest of these steps.


Step 3: Check if the key was used

Before you move on, look for signs of misuse. This tells you how serious the exposure was.

For OpenAI keys: Go to platform.openai.com → Usage. Look for unusual spikes or usage you didn't create.

For Stripe keys: Go to the Dashboard → Logs. Filter for recent API calls. Look for charges or refunds you didn't initiate.

For AWS keys: Go to CloudTrail → Event History. Look for actions you didn't take, especially in regions you don't use.

For email providers (SendGrid, Mailgun, Postmark): Check your sending logs for messages you didn't send.

If you see evidence of misuse, document it (screenshots of logs and timestamps) before anything gets rotated or deleted. You may need this if you have to report a breach or dispute charges.


Step 4: Remove the key from your code

Now fix the root cause: the key should never have been in your code.

If the key is in your current code (a .env file, a config file, a source file):

  1. Replace the hardcoded key with an environment variable reference:
    // ❌ Before
    const client = new OpenAI({ apiKey: 'sk-abc123...' })
    
    // ✅ After
    const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
    
  2. Add the new key to your deployment environment variables (Vercel, Netlify, Heroku, Railway — wherever you host).
  3. Test that your app still works with the environment variable.

If the key is in a .env file: Environment files shouldn't be committed to git. Add .env and .env.local to your .gitignore:

.env
.env.local
.env.*.local

Step 5: Purge the key from your git history

This is the step most founders skip — and it matters. Even if you delete the key from your current code, it may still exist in your git history. Anyone who clones your repo can run git log and find it.

If your repository is private, the risk is lower, but you should still clean the history before it ever becomes public.

The fast approach (works for recent commits):

If the key was only added in the last few commits and you haven't pushed to a shared repo:

git rebase -i HEAD~3  # Replace 3 with how many commits back the key was added

Mark the commit that added the key as "edit", then amend it to remove the key.

The thorough approach (use git-filter-repo):

For keys that have been in the history for a while, or if you want to be thorough:

pip install git-filter-repo
git filter-repo --path-glob '*.env' --invert-paths
# Or to remove a specific string:
git filter-repo --replace-text <(echo 'sk-abc123...==>REMOVED')

After cleaning history, force-push:

git push origin main --force

⚠️ Warning: rewriting git history is destructive. If others are working on the repo, they'll need to re-clone. Coordinate with anyone who has a copy.

If the repo was ever public: Assume the key has already been harvested. Rotate scanners monitor GitHub continuously for exposed keys. Cleaning the history is still worth doing, but treat the old key as compromised regardless.


Step 6: Check where else the key might be

API keys have a way of spreading. Before you declare victory, check these locations:

Version control:

  • GitHub, GitLab, or Bitbucket search: search your repos for the key string
  • Any forks of your repo (even private repos can be forked)

Environment files:

  • .env, .env.local, .env.development, .env.production
  • Any file that starts with .env or contains config

Frontend bundles:

  • Your compiled JavaScript files in /.next/, /dist/, /build/
  • The key might be gone from your source but still in an old compiled bundle

Log files:

  • If you ever console.log(process.env) for debugging, your logs may contain all your secrets

CI/CD pipelines:

  • Build logs sometimes print environment variable names and occasionally their values
  • Check your GitHub Actions, Vercel deployment logs, or whatever CI you use

Step 7: Set up monitoring so this doesn't happen silently again

Now that you've fixed the immediate problem, put systems in place to catch future exposures:

Enable GitHub secret scanning: If your repo is on GitHub, go to Settings → Code security and analysis → Secret scanning → Enable. GitHub will automatically flag any future commits that contain known API key formats.

Use GitGuardian: Free tier available at gitguardian.com. It watches your repos for secret patterns and alerts you immediately.

Run VibeScan regularly: VibeScan scans your live app for exposed secrets in page source and JavaScript bundles — the place secrets end up when they get bundled into the frontend by accident. Run it after every major deployment.

Review your app before every deploy: Before pushing to production, do a quick search for common key patterns:

grep -r "sk-" ./src
grep -r "pk_live" ./src
grep -r "AKIA" ./src  # AWS access keys

The harder question: was any data accessed?

If your key was exposed for more than a few hours, or if it was in a public repository, someone may have used it. Here's how to think about what happened:

If it was an OpenAI key: Worst case, someone ran up charges on your account. Check usage and dispute with OpenAI support if there are charges you didn't generate.

If it was a Stripe key: Check for any charges or refunds you didn't initiate. If the key had webhook access, check for endpoint registrations you didn't create.

If it was a database key (Supabase, Firebase): Check your database for records you didn't create or modifications you didn't make. This is the most serious case — user data may have been accessed or deleted.

If it was a Twilio or SendGrid key: Check your logs for messages you didn't send. These keys are commonly used to send spam or phishing messages at your expense.

For any case where you believe user data was accessed, consult with a lawyer about your notification obligations. Many jurisdictions require notifying affected users within 72 hours of discovering a breach.


Summary: the five-minute action plan

If you're skimming this in a panic:

  1. Revoke the key now — find it in the provider's dashboard and delete or rotate it
  2. Create a new key — don't leave your app broken
  3. Check for misuse — look at usage logs for the last 24-72 hours
  4. Remove from code — use environment variables instead
  5. Clean git history — especially if the repo was ever public

Then run VibeScan to confirm no other secrets are visible in your live app. The whole process takes about 30 minutes and is much less painful than cleaning up after a real breach.

Scan your app for exposed secrets →