PL-011highCode

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.

what history looks like (illustrative)
$ 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

check-pl-011.sh
# 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

  1. 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.
  2. Stop it happening again: add env files to .gitignore, keep secrets in your host's secret store, and re-check after each change.
  3. Optionally, rewrite history so the old commits disappear from your repo. It's hygiene, not a fix, and it changes every commit id.
optional clean-up
# 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

key scan · report excerpt
[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
synthetic exampleMasked, not real keys

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.

Guides

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.

Free for your first appReads your public repo onlyOr run the free static RLS check

Last reviewed 10 Nov 2026. Finding IDs are stable: link to them freely. Spotted a mistake? Tell us.