← Back to list

Secrets in Your Git Repo: How to Find and Remove Them

Part 2 of the “Security Engineers Forget” series. “We’d never commit an API key.” Your Git history disagrees.

Nazmul Hasan · 2026-07-20 07:01 · 0 claps · 3.4 min read
#security #devsecops #github #management-secrets #software-engineering
Open on Medium ↗
Wiki topics: BIZ · Business Strategy 🔓 · Open Source

Secrets in Your Git Repo: How to Find and Remove Them

Part 2 of the “Security Engineers Forget” series. “We’d never commit an API key.” Your Git history disagrees.

Every team is certain it doesn’t happen to them. And every week, security researchers find tens of thousands of live credentials — AWS keys, database passwords, API tokens, private keys — sitting in public GitHub repositories. Not from careless beginners only; from real companies, in real production systems. Leaked secrets are one of the most common and most damaging security failures, and the reason is simple: a secret in code is incredibly easy to commit and incredibly hard to truly remove.

The good news is this is a solved problem with well-known practices. The bad news is the practices only help if you adopt them before the leak. Here’s how secrets get in, why deleting them isn’t enough, and how to keep them out for good.

A secret committed to Git isn’t a mistake you can undo. The moment it’s pushed, assume it’s compromised — because Git remembers everything, and so does everyone who cloned the repo.

How Secrets Get Committed

It’s almost never malicious — it’s friction and habit:

# "Just for testing, I'll hardcode it and fix it later" (later never comes)
STRIPE_KEY = "sk_live_4eC39HqLyjWDarjtT1zdp7dc"
DB_PASSWORD = "prod_password_123"
# Or it sneaks in via a config file nobody meant to commit
# .env  ← contains every production secret, accidentally `git add .`-ed

The classic paths: hardcoding “temporarily,” committing a .env file with git add ., pasting a key into a config to debug, or checking in a cloud credentials file. Each is one distracted moment, and the secret is now permanent history.

Why Deleting It Later Doesn’t Work

Here’s the trap that catches everyone. You notice the key, delete it, commit “removed secret,” and feel safe. You are not safe. Git is a history — the secret still lives in every previous commit, recoverable by anyone with the repo:

# The "removed" secret is one command away for anyone who has the repo
git log -p | grep -i "sk_live"      # there it is, in the history

If that repo was ever public, or anyone untrusted cloned it, the secret is compromised — permanently. Which leads to the only correct response:

Fix #1: Rotate First, Then Clean

When a secret is exposed, the priority order is non-negotiable:

  1. Rotate it immediately. Revoke the leaked credential and issue a new one. This is the only action that actually protects you — it makes the leaked value worthless. Do this first, before anything else.
  2. Then scrub it from history (tools like git filter-repo or BFG) if needed, and force-push — but understand this is cleanup, not protection. The exposed secret must already be dead.

Repeat the mantra: a leaked secret is not “removed” by deleting it. It’s neutralized by rotating it. Cleaning history without rotating is theater.

Fix #2: Keep Secrets Out of Code Entirely

The real fix is architectural: secrets should never be in the code in the first place. They belong in the environment or a secrets manager:

import os
STRIPE_KEY = os.environ["STRIPE_KEY"]        # injected at runtime, never committed
# For anything serious, a real secrets manager:
#   AWS Secrets Manager, HashiCorp Vault, Doppler, GCP Secret Manager
# — centralized, access-controlled, auditable, and rotatable.

And ignore the files that hold local secrets so they can never be committed:

# .gitignore
.env
.env.local
*.pem
credentials.json

Commit a .env.example with blank values so teammates know what's needed, never the real thing. The rule: code goes in Git; secrets go in the environment.

Fix #3: Add a Net That Catches Leaks Automatically

Humans forget, so automate the catch. Scan for secrets before they’re committed and continuously after:

  • Pre-commit hooks (gitleaks, detect-secrets, trufflehog) that block a commit containing something that looks like a key — stopping the leak at the source.
  • CI secret scanning on every push as a backstop.
  • GitHub secret scanning / push protection, which many providers now offer free and which can reject the push outright.

A pre-commit scanner is the highest-leverage safeguard: it catches the mistake in the half-second before it becomes permanent history, while it’s still trivially fixable.

Putting It Together

  1. If leaked, rotate first — revoke and reissue; that’s the only real protection.
  2. Keep secrets in the environment / a secrets manager, never in code.
  3. **.gitignore secret files**; commit a blank .env.example.
  4. Automate detection — pre-commit hooks + CI scanning + push protection.

The Takeaway

“We’d never commit a secret” is exactly the confidence that lets secrets get committed, because the safeguards never get set up. A credential in Git is uniquely dangerous: trivially easy to add, impossible to truly delete, and live the moment it’s pushed. The discipline that prevents it is well-established — keep secrets out of code entirely, ignore the files that hold them, and run a scanner that blocks leaks before they happen. And if one does slip through, remember the only response that matters: rotate it immediately, because deleting it just hides it from you, not from anyone who already has your repo.

This is Part 2 of the Security Engineers Forget series. Next up: authentication vs authorization — two words people use interchangeably, and the confusion that creates real holes.

Have you ever had to do an emergency key rotation after a leak? 👇


메타데이터
post_id
3fd7916d30d2
slug
secrets-in-your-git-repo-how-to-find-and-remove-them-3fd7916d30d2
url
https://medium.com/@nazmul_hasan/secrets-in-your-git-repo-how-to-find-and-remove-them-3fd7916d30d2
canonical_url
https://medium.com/@nazmul_hasan/secrets-in-your-git-repo-how-to-find-and-remove-them-3fd7916d30d2
author_url
https://medium.com/@nazmul_hasan
status
ok
fetched_at
2026-09-07 13:10:34