Blog Post

The .env File Sitting in Your Git History Right Now

Developers accidentally commit secrets to git repos every day. Learn how to find exposed secrets in your git history, clean them up, and prevent it from happening again.

|7 min read
env file git historycommitted secrets gitgit secret leakremove secrets gitgitguardian

Let me tell you something that might ruin your afternoon. There is a very good chance that right now, sitting in the git history of one of your repositories, there is a .env file with real credentials in it. Or a config file with a database URL. Or a hardcoded API key in a source file from eighteen months ago that somebody thought they deleted.

The file is not in your current codebase. You removed it. You added it to .gitignore. You thought the problem was solved.

But git never forgets. Every commit is permanent. And that .env file you removed six months ago? It is still there in the history, fully intact, waiting for someone to find it.

The Scale of the Problem

This is not a rare edge case. This is one of the most common security issues in software development.

GitGuardian's 2024 State of Secrets Sprawl report found over 12 million new secrets exposed in public GitHub repositories in a single year. That is 12 million API keys, database passwords, cloud credentials, and private keys pushed to version control by developers who either did not realize what they were committing or assumed their repo was private.

And that is just public repositories. The number of secrets in private repos is impossible to measure, but it is almost certainly larger. Private repos give developers a false sense of security. "It is private, so it is fine." Except private repos get cloned to laptops that get lost. Private repos get shared with contractors who leave. Private repos get accidentally made public during organization restructuring.

Every one of those 12 million exposed secrets is a door left unlocked. Some of them lead to test environments that do not matter. Some of them lead to production databases with customer data.

How It Happens

Here is the thing: nobody commits secrets on purpose. It happens because the default workflow makes it easy and the consequences are invisible.

The classic .env commit. A developer creates a new project. They set up the .env file with their development credentials. They run git add . to stage everything. They commit. The .env file goes in with everything else. Maybe they catch it right away and add .env to .gitignore. But the damage is done. That first commit has the file, and it is in the history forever. The "just this once" hardcode. A developer is debugging a tricky API integration. They hardcode the API key directly in the source file to test something quickly. They fix the bug, forget to remove the hardcoded key, and commit the file. The key is now in the codebase. The config file rename. A team renames their config file from config.yml to settings.yml. The .gitignore covers settings.yml but not config.yml. The old file with real credentials was tracked before the rename and is still in the history. The merge accident. Two developers work on different branches. One adds credentials to a file that the other does not know about. The merge goes through, and the credentials end up in main.

How to Check Your Repos Right Now

Here is the scary-but-necessary part. You should actually check. Here are two ways to do it:

Using git log (quick and dirty):
bash
# Search git history for common secret patterns

git log -p --all -S 'password' -- '*.env' '*.yml' '*.json'

git log -p --all -S 'API_KEY' -- '*.env' '*.yml' '*.json' '*.ts' '*.js'

git log -p --all -S 'sk_live' -- . # Stripe live keys

git log -p --all -S 'AKIA' -- . # AWS access keys

Using gitleaks (thorough):
bash
# Install gitleaks

brew install gitleaks # macOS

# Scan entire repo history

gitleaks detect --source . --verbose

Gitleaks will scan every commit in your repository history and report any secrets it finds. The output tells you which file, which commit, and what type of secret was detected.

If you run this and find nothing, congratulations. You are in the minority. If you find something, do not panic. But do act quickly.

How to Clean Up

Found secrets in your history? Here is the process:

Step 1: Rotate immediately. Before you do anything else, rotate every credential that was exposed. Generate a new API key, change the password, create a new token. The old one should be considered compromised regardless of whether anyone actually found it. This is the most important step and it comes first. Step 2: Remove from history (optional but recommended). You can rewrite git history to remove the sensitive files entirely. The most common tool for this is BFG Repo-Cleaner:
bash
# Remove a specific file from all history

java -jar bfg.jar --delete-files .env

# Remove specific strings

echo "sk_live_old_key_here" > passwords.txt

java -jar bfg.jar --replace-text passwords.txt

# Clean up

git reflog expire --expire=now --all

git gc --prune=now --aggressive

git push --force

Step 3: Verify the cleanup. Run gitleaks again after rewriting history to confirm the secrets are gone. Step 4: Notify your team. Everyone who has cloned the repo needs to re-clone after the history rewrite. Old clones still contain the original history with the secrets.

How to Prevent It From Happening Again

Cleaning up is necessary but not sufficient. You need layers of prevention so this does not happen again:

Layer 1: A proper .gitignore from day one. Every new project should start with a .gitignore that covers .env files, key files, and credential files. Do not wait until after the first commit. Layer 2: Pre-commit hooks. Install gitleaks or detect-secrets as a pre-commit hook. Every commit gets scanned automatically. If a secret is detected, the commit is blocked before it ever reaches the repository. Layer 3: Get secrets out of files entirely. This is the real fix. If your credentials are not in files on your local machine, they cannot be committed to git. It is that simple.

ConfigShield's .env import gets your secrets out of files and into encrypted storage. Instead of keeping a .env file on your machine permanently, you pull secrets from ConfigShield when you need them:

bash
# Pull secrets when you need them

configshield pull --project my-app --env development

# Work on your code

# Delete the .env file when you are done (it is in .gitignore anyway)

# But even if you forget, the pre-commit hook catches it

Your secrets live in ConfigShield, encrypted with AES. They are not files on disk waiting to be accidentally committed. They are not strings in your source code. They are pulled on demand and discarded when not needed.

The Five-Minute Setup That Prevents the Next Leak

Here is the practical path forward:

  • 1.Run gitleaks on your repos today. Know what is exposed.
  • 2.Rotate any exposed credentials immediately. Do not wait.
  • 3.Import your .env files into ConfigShield. Five minutes, free plan.
  • 4.Install a pre-commit hook. Another five minutes.
  • 5.Delete the .env files from your machine. Pull from ConfigShield when needed.
  • That is it. Fifteen minutes of work, and you have eliminated one of the most common attack vectors in software development.

    The .env file in your git history did not put itself there on purpose. It got there because the default workflow made it easy. Change the default, and the problem goes away.

    Import your .env into ConfigShield. Get secrets out of files and into encryption.
    </>

    Secure Your Secrets Today

    Free forever for solo developers. AES encryption, audit trails, and CLI access in 30 seconds.

    </>Start Free