How to Never Accidentally Commit Secrets to Git Again
A practical guide to preventing accidental secret commits: .gitignore patterns, pre-commit hooks, secret scanning tools, and automated protection strategies.
It happens faster than you think. You are in the flow, staging files with git add ., writing a quick commit message, and pushing to remote. Twenty minutes later, GitHub sends you an email: "We found a secret in your push." Your AWS access key is now in your public commit history. Even if you delete the file, the secret lives in git's history forever.
This guide covers every layer of defense you should have in place so this never happens to you.
Layer 1: A Bulletproof .gitignore
Your first line of defense is making sure sensitive files are never tracked in the first place. Every project should have a .gitignore that covers these patterns:
# Environment files
.env
.env.*
.env.local
.env.development
.env.staging
.env.production
!.env.example
# Credentials
*.pem
*.key
*.p12
*.pfx
credentials.json
service-account.json
google-credentials.json
# IDE and OS
.idea/
.vscode/settings.json
.DS_Store
# Build artifacts that might contain embedded secrets
.next/
dist/
build/
The !.env.example line is important: it tells git to track .env.example even though all other .env* files are ignored. This file should contain placeholder values and serves as documentation for your team.
git status before every commit. If you see a file you did not expect, investigate before staging it.
Layer 2: Pre-Commit Hooks
Even with a perfect .gitignore, mistakes happen. Someone renames a file. Someone creates a new config file that is not covered by existing patterns. Pre-commit hooks catch these mistakes before they enter your git history.
Using detect-secrets
detect-secrets by Yelp is one of the best tools for catching secrets in staged files:
# Install
pip install detect-secrets
# Create a baseline (marks existing known secrets)
detect-secrets scan > .secrets.baseline
# Install the pre-commit hook
# In .pre-commit-config.yaml:
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
Using git-secrets by AWS
AWS Labs' git-secrets specifically catches AWS access keys and other common credential patterns:
# Install
brew install git-secrets # macOS
# Register AWS patterns
git secrets --register-aws
# Install hooks for this repo
git secrets --install
# Now any commit containing an AWS key will be blocked
Using gitleaks
gitleaks scans for a wide range of secret patterns and supports custom rules:
# Install
brew install gitleaks # macOS
# Scan staged changes before committing
gitleaks protect --staged
# Add as a pre-commit hook
# In .pre-commit-config.yaml:
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
Layer 3: CI/CD Secret Scanning
Pre-commit hooks protect individual developers, but CI/CD scanning protects the entire team. If someone bypasses their local hooks (or has not set them up), the CI pipeline catches the mistake.
GitHub Secret Scanning
If you use GitHub, enable "Secret scanning" in your repository settings under "Security." GitHub automatically scans every push for known secret formats (AWS keys, Stripe keys, database URLs, etc.) and alerts you immediately.
GitHub also partners with service providers. If your Stripe key is detected, GitHub notifies Stripe, and the key can be automatically revoked.
GitLab Secret Detection
GitLab offers built-in secret detection as part of its CI/CD pipeline:
# .gitlab-ci.yml
include:
- template: Security/Secret-Detection.gitlab-ci.yml
Layer 4: The Nuclear Option — git filter-branch
If a secret has already been committed, deleting the file is not enough. The secret exists in your git history and can be recovered with git log or git reflog. You need to rewrite history.
# Using BFG Repo-Cleaner (faster than filter-branch)
# Download bfg.jar from https://rtyley.github.io/bfg-repo-cleaner/
# Remove a specific file from all history
java -jar bfg.jar --delete-files .env
# Remove specific strings
echo "sk_live_abc123" > secrets-to-remove.txt
java -jar bfg.jar --replace-text secrets-to-remove.txt
# Clean up and force push
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --force
Important: After rewriting history, rotate every secret that was exposed. Rewriting git history removes the secret from future clones, but anyone who already cloned the repository still has it.
Layer 5: Stop Having Secrets in Files at All
The best way to prevent committing secrets to git is to not have secret files in your working directory in the first place.
With ConfigShield, secrets live in an encrypted vault and are pulled on demand:
# Pull secrets when you need them
configshield pull --project my-app --env development
# The .env file is created locally and already in your .gitignore
# When you are done, delete it
rm .env
Since secrets are always available via configshield pull, you never need to keep .env files around permanently. They are ephemeral: pulled when needed, deleted when not.
The Checklist
Use this checklist for every new project:
- •Add comprehensive
.envpatterns to.gitignore - •Install a pre-commit hook (
detect-secrets,gitleaks, orgit-secrets) - •Enable secret scanning in your Git hosting platform
- •Store secrets in a manager instead of local files
- •Rotate any secret that has ever appeared in a commit
It takes 15 minutes to set up all five layers. The alternative is explaining to your CTO why your production database was exposed on GitHub.
Start managing secrets securely with ConfigShield →Secure Your Secrets Today
Free forever for solo developers. AES-256 encryption, audit trails, and CLI access in 30 seconds.