Key still in git history
You deleted the key. Every old commit still has it, and so does every clone and fork.
- Severity
- High
- Who can exploit it
- Anyone who can read the repo
- Found by
- Key scan of the full git history (every check)
- Lab proof
- Report lists each key with where to rotate it
What it is
Deleting a key from your code doesn't remove it from the repository. Git keeps every version of every file, so a committed .env or a key pasted into a component is still readable in the old commit, by anyone who can read the repo. For a public repo, that is anyone.
The PatchLabs key scan reads the code and the full git history of every repo it checks, for AI, payment and database keys. Values are masked in the report, with where each key was found and where to rotate it.
Example of vulnerable code
Simplified from the patterns we see in AI-built apps. Synthetic: not taken from any real app.
$ git log --oneline -- .env
a41c9e2 remove .env (oops)
7f03b18 add stripe checkout # .env with sk_live_… committed here
$ git show 7f03b18:.env
STRIPE_SECRET_KEY=sk_live_51N… # still readable today
Check it yourself
# 1. Commits that added or removed something key-shaped (all branches)
git log --all -p -G 'sk_live_|sk-proj-|sk-ant-|service_role|sb_secret_|AIza' \
--format='%h %ad %s' --date=short | grep -E '^[0-9a-f]{7}|^[+-].*(sk_|AIza|service_role|sb_secret_)' | head -60
# 2. Was an env file ever committed?
git log --all --format='%h %ad %s' --date=short -- .env '*.env' '.env.*'
The fix
- Rotate every key that was ever committed, at the provider (the report links to the right page for each). This is the fix. Forks, clones and caches keep old commits, so a key that has been public must be treated as known.
- Stop it happening again: add env files to
.gitignore, keep secrets in your host's secret store, and re-check after each change. - Optionally, rewrite history so the old commits disappear from your repo. It's hygiene, not a fix, and it changes every commit id.
# Only after rotating. Run on a fresh clone; collaborators must re-clone afterwards.
git filter-repo --invert-paths --path .env
echo ".env*" >> .gitignore
git push --force --all
Code findings come with the file, the line and a one-line fix in the report, for your engineer to make. PatchLabs never pushes to your repo.
How PatchLabs finds it
[SCAN] full history · 214 commits .env (deleted in a later commit) payment key sk_l…4f2a LEAK AI key sk-p…9bQe LEAK [ACTION] rotate both at the provider add .env* to .gitignore
We can't check whether a key still works without using it, and we never use keys we find. So the report doesn't claim the problem is solved. It lists each key, masked, with the commit or file it came from and the page where you rotate it.
When the pattern is intended
Some key-shaped strings are fine to commit: the Supabase public key (meant for browsers), test-mode keys such as sk_test_…, and placeholder values in .env.example. The report shows the file or commit for every key it finds, so you can tell these apart quickly. If a flagged key was revoked long ago, there is nothing more to do.
Related findings
AI, payment or database key in the code
A secret key for an AI, payment or database service is sitting in your current code, readable by anyone who can read the repo.
PL-010Service role key in client code
The key that ignores every access rule, shipped to every visitor's browser.
PL-001Anonymous visitor can read personal data
Anyone with your app's public key can read emails, phone numbers or addresses.
Guides
- What to do in the first hour after a leak
- How to rotate a leaked API key and clean your git history
- Pre-launch security checklist for vibe-coded apps
Free check
Does your app have PL-011?
Paste your public repo. PatchLabs Code reads it for this and every other code finding, and the Lab rebuilds your database to test who can read what.
Last reviewed 10 Nov 2026. Finding IDs are stable: link to them freely. Spotted a mistake? Tell us.