◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude Code
⟐ Claude Code/2026-05-12Intermediate

Accidentally Committed API Keys to Git — Emergency Response with Claude Code

Step-by-step emergency guide for when you accidentally commit .env API keys to git. Covers immediate key rotation, removing secrets from git history with Claude Code, and preventing it from happening again.

troubleshooting92security19git18envapi-keyclaude-code132emergency

It's a moment most developers dread: you've just pushed a commit and realized your .env file — the one with all your real API keys — went along for the ride.

Having built and shipped personal apps continuously since 2014, I've watched this happen more times than I'd like to admit — to myself and to developers I know. AdMob keys, Stripe production secrets, Anthropic API keys. The more services your personal project integrates, the higher the risk of a .env slipping through.

This guide walks you through what to do after it's already happened, in the order that actually matters. Done methodically, you can close the window within 30 minutes.

First 5 Minutes: Rotate Your Keys Before Anything Else

Rewriting git history doesn't undo the past. Between the moment of the push and now, automated scanners — and potentially bad actors — may have already copied those keys. Rotation is the only thing that makes the leaked credentials useless.

Anthropic API key:

  1. Open console.anthropic.com → API Keys
  2. Find the exposed key and click Revoke
  3. Generate a new key and update your local .env

Google AdMob / Firebase:

  1. Go to console.firebase.google.com → Project Settings → Service Accounts or API Keys
  2. Disable the exposed key and create a replacement

Stripe:

  1. Open dashboard.stripe.com → Developers → API keys
  2. For production keys, use Roll to instantly invalidate and replace in one step

Finish rotation before you touch git. A rotated key is worthless to anyone who grabbed it.

Assess the Damage

Once your keys are safe, understand the scope of the exposure:

# Find commits that included .env
git log --all --full-history -- .env
 
# Search for the key pattern itself (replace with your key prefix)
git log -S "sk-ant-" --all --oneline
git log -S "sk_live_" --all --oneline

If the repo is on GitHub, check Settings → Secret scanning → Alerts. GitHub automatically detects patterns for major providers (Anthropic, AWS, GCP, Stripe, OpenAI, and more) and will alert you if it found anything. An open alert means GitHub caught it; close the alert once you've completed the steps below.

Remove the Keys from Git History

Option 1: git-filter-repo (Recommended)

# Install git-filter-repo
pip install git-filter-repo --break-system-packages
# or on macOS
brew install git-filter-repo
 
# Remove .env from the entire history
cd /path/to/your-repo
git filter-repo --path .env --invert-paths --force
 
# Force-push the rewritten history
git remote add origin https://github.com/your-user/your-repo.git
git push origin --force --all
git push origin --force --tags

--invert-paths keeps everything except the specified path. After this, .env will not exist in any commit in your entire history.

Option 2: git filter-branch (Older Environments)

git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch .env" \
  --prune-empty --tag-name-filter cat -- --all
 
git push origin --force --all

Asking Claude Code to Do It

You can delegate this to Claude Code with a clear prompt:

Remove the .env file from the entire git history using git filter-repo.
Use --invert-paths to exclude .env from all commits.
Then force-push to origin at https://github.com/your-user/your-repo.git.
Do not ask for confirmation — proceed immediately.

If Claude Code pauses and asks for confirmation before rewriting history, respond with "Please proceed without confirmation." It will continue.

Notify Collaborators (Team Projects Only)

Force-pushing rewrites shared history, which means anyone else's local clone will be out of sync. After the push, ask every collaborator to run:

git fetch origin
git reset --hard origin/main

For solo projects — which covers most indie developers — skip this step entirely.

Add .env to .gitignore

Prevent the next incident by confirming your ignore rules are correct:

# Check if .env is already ignored
cat .gitignore | grep -E "^\.env$"
 
# Add it if missing
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env.*.local" >> .gitignore
 
git add .gitignore
git commit -m "chore: add .env to gitignore"
git push origin main

If .env was already in .gitignore but still got committed, it was likely added to git tracking before the ignore rule existed. Remove it from tracking without deleting the file:

git rm --cached .env
git commit -m "chore: untrack .env"

Close the GitHub Secret Scanning Alert

If GitHub opened an alert when it detected the key pattern, go to Security → Secret scanning → Alerts, open the specific alert, and mark it as Resolved (revoked). GitHub will verify that the secret is no longer active and close the alert.

The detection speed surprised me the first time I saw it in action. When a test Stripe key ended up in a commit for one of my wallpaper app's backend repos, Stripe's own monitoring flagged it before GitHub's email even arrived. These systems are fast — which is exactly why key rotation must come first.

Prevention: Build the Safety Net

Use .env.example for documentation

Commit a .env.example with placeholder values instead of the real file:

# .env.example — safe to commit
ANTHROPIC_API_KEY=your_api_key_here
STRIPE_SECRET_KEY=your_stripe_key_here
ADMOB_APP_ID=your_admob_id_here
 
# .env — never commit this
ANTHROPIC_API_KEY=sk-ant-api03-xxxxx
STRIPE_SECRET_KEY=sk_live_xxxxx
ADMOB_APP_ID=ca-app-pub-xxxxx

Add a pre-commit hook

A simple shell hook will catch .env before it ever reaches a commit:

# .git/hooks/pre-commit (make it executable: chmod +x)
#!/bin/bash
if git diff --cached --name-only | grep -q "^\.env$"; then
  echo "❌ .env is staged for commit. Run: git rm --cached .env"
  exit 1
fi

Tell Claude Code in CLAUDE.md

Adding a note in your project's CLAUDE.md helps Claude Code make the right call when it encounters .env during automated tasks:

## Security Rules
- Never add .env to git staging or commits
- Pass API keys through environment variables, not hardcoded values
- Before running `git add .`, confirm .env is not included

The order matters: rotate first, rewrite history second, prevent third. Jumping straight to the git cleanup while the old key is still active leaves you exposed during the time it takes.

If you're reading this before it's happened to you, setting up the pre-commit hook right now takes about two minutes and will save you a much longer conversation with yourself later.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⟐ Claude Code2026-08-28
A small script that catches invisible characters in plugin names before you install
Control characters and zero-width characters hiding in plugin or skill names are invisible in a terminal listing. I built six deliberately confusing names, compared what ls actually shows, and wrote a short check you can run before installing anything — plus an honest note on what that check misses.
⟐ Claude Code2026-05-24
When Claude Code's Sequential Edits Cascade into Failure — Fixing 'old_string not found' and 'not unique' on the Same File
Run several Edits against the same file in one turn and the second or third one suddenly fails with 'not found' or 'not unique'. The cause is order-dependence inside a single context snapshot, and a Read + scoped patches usually rescue it.
⟐ Claude Code2026-05-10
When Claude Code's Read Doesn't Reach the End of a File — Catching the PARTIAL view Notice and Sizing offset/limit
When Read returns only part of a large file, Claude Code says so with a PARTIAL view notice. Here is how to catch it, and how to size offset and limit by byte budget rather than line count, with measurements from my own sandbox.