Prevent Committing Secrets!
Amjad Hossain
Lead Software Engineer, Problem solver & Polyglot Programmer. #PromptEngineering
In the fast-paced world of software development, security mistakes often happen—not always because developers don’t know better, but because of deadlines, pressure, or a lack of process. One of the most common and dangerous mistakes? Accidentally committing API keys, passwords, or database credentials to version control.
Once a secret is pushed to a repository, it’s at risk—whether it’s a public or private repo. Attackers can scrape repositories, expose sensitive data, and even gain unauthorized access to critical systems. Unfortunately, many startups and teams without experienced developers or strong code review processes fall into this trap, especially under pressure to "just get it working."
I would like to share here some practical ways for developers/leads to prevent secrets from ever being committed to Git repositories.
Why Committing Secrets is a Problem
Deploy crypto-mining (which consume expensive EC2 instances and GPU power).
Set up proxy services for illegal activities.
Store large amounts of pirated content on S3.
Solution? Proactive Prevention!
Step 1: Use .gitignore to Prevent Accidental Commits
First, make sure that sensitive files are ignored by Git. Add the following to your .gitignore file:
# Ignore environment files
.env
*.pem
*.pfx
*.key
*.crt
*.enc
config/*.json
secrets.yml
? This ensures that Git does not track these files.
Step 2: Use Environment Variables Instead of Hardcoded Secrets
Instead of storing credentials in code, use environment variables and key vault/manager.
Linux & Mac:
echo "export API_KEY='your_api_key'" >> ~/.bashrc
source ~/.bashrc
Windows (PowerShell):
[System.Environment]::SetEnvironmentVariable("API_KEY", "your_api_key", [System.EnvironmentVariableTarget]::User)
Your app can then read it using:
Python: os.getenv("API_KEY")
Node.js: process.env.API_KEY
C# (.NET): Environment.GetEnvironmentVariable("API_KEY")
Step 3: Add a Pre-Commit Hook to Stop Secret Commits
Git pre-commit hooks block secrets before they reach your repository.
Setting Up a Git Pre-Commit Hook (Works on Mac, Linux, Windows WSL, or Git Bash)
1. Navigate to Your Repository
cd /path/to/your/repository
2. Create the Hooks Directory (if not exists)
mkdir -p .git/hooks
3. Create the Pre-Commit Hook File
nano .git/hooks/pre-commit
Or for Windows (PowerShell):
New-Item -Path .git/hooks/pre-commit -ItemType File
4. Copy and Paste the Script
#!/bin/sh
SECRET_PATTERN='(AWS|API|SECRET|TOKEN|PASSWORD|PRIVATE|CERT|DB)_?(KEY|TOKEN|SECRET|PWD|PASS|CRED|CERT)'
if git diff --cached | grep -E "${SECRET_PATTERN}"; then
echo "? Secret detected! Commit rejected."
exit 1
fi
5. Save and Exit
If you're using nano, press CTRL + X, then Y, and Enter to save.
领英推荐
6. Make the Hook Executable
chmod +x .git/hooks/pre-commit
? Now, if you try to commit a secret, Git will reject it!
Step 4: Scan Repositories for Secrets
If secrets might already be in your repo, scan it using:
Using GitLeaks (Cross-Platform)
# Install GitLeaks on Mac & Linux
curl -sSfL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks-linux-amd64 -o gitleaks
chmod +x gitleaks && sudo mv gitleaks /usr/local/bin/
# Windows (PowerShell - Run as Administrator)
iwr -useb https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks-windows-amd64.exe -OutFile gitleaks.exe
Now, scan your repo:
gitleaks detect --verbose --redact
? If secrets are found, remove them immediately!
Step 5: Remove Secrets from Git History
If a secret was already committed, removing it from code is NOT enough! It still exists in Git history.
Use BFG Repo-Cleaner to remove secrets safely:
bfg --delete-files secret.json
Or rewrite history for API keys:
bfg --replace-text banned-words.txt
?? Don't forget to force push:
git push --force
? This removes secrets from history while keeping commits intact.
Step 6: Automate Secret Scanning in GitHub and Azure DevOps
To enforce security in CI/CD pipelines, use GitLeaks in GitHub Actions and Azure DevOps Pipelines.
GitHub Actions:
Create .github/workflows/secret-scan.yml
name: Secret Scanning
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run GitLeaks
run: |
curl -sSfL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks-linux-amd64 -o gitleaks
chmod +x gitleaks && sudo mv gitleaks /usr/local/bin/
gitleaks detect --verbose --redact --exit-code 1
Azure DevOps Pipeline:
Create azure-pipelines.yml in root directory
trigger:
branches:
include:
- main
- develop
pool:
vmImage: 'ubuntu-latest'
steps:
- script: |
curl -sSfL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks-linux-amd64 -o gitleaks
chmod +x gitleaks && sudo mv gitleaks /usr/local/bin/
gitleaks detect --verbose --redact --exit-code 1
AWS DevOps Pipeline:
Create buildspec.yml in root directory of repository
version: 0.2
phases:
install:
runtime-versions:
golang: latest
commands:
- echo "Installing GitLeaks..."
- curl -sSfL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks-linux-amd64 -o gitleaks
- chmod +x gitleaks && mv gitleaks /usr/local/bin/
build:
commands:
- echo "Running GitLeaks scan..."
- gitleaks detect --verbose --redact --exit-code 1
? This ensures secrets never reach production!
Summary