Secrets in Committed .env Files
A .env file containing real credentials committed to git, making all secrets permanently accessible to anyone with repo access — including through git history.
How It Works
git tracks every version of every file. When you commit a .env with real secrets and later delete it, the secrets remain in every prior commit. Anyone who clones the repo can run `git log -p` and retrieve the secrets. For public repos, GitHub also indexes the content for search.
# BAD: .env committed to git (never do this)
DATABASE_URL=postgresql://user:realpassword@db.host/prod
STRIPE_SECRET_KEY=sk_live_abc123
ANTHROPIC_API_KEY=sk-ant-real-key-here# GOOD: .env.example with placeholders only
DATABASE_URL=postgresql://user:password@localhost/mydb
STRIPE_SECRET_KEY=sk_live_your_key_here
ANTHROPIC_API_KEY=sk-ant-your-key-here
# Real values go in .env (gitignored) or your deployment platformReal-World Example
Twitch's 2021 breach included internal tool secrets that had been committed to internal repos years earlier. Even 'private' repos can be exposed through insider threats, acquired companies, or misconfigured access controls.
How to Prevent It
- Add .env and .env.local to .gitignore before your very first commit
- Only commit .env.example with placeholder values, never real credentials
- If you already committed secrets, rotate all exposed credentials immediately
- Use git filter-repo or BFG Repo-Cleaner to purge secrets from git history
- Use truffleHog or git-secrets as a pre-commit hook to block future secret commits
Affected Technologies
Data Hogo detects this vulnerability automatically.
Scan Your Repo FreeRelated Vulnerabilities
Hardcoded API Keys
criticalAPI keys, tokens, or secrets written directly in source code, making them visible to anyone with repo access — including public GitHub repositories.
No Input Validation
mediumUser-supplied data sent directly to databases or external APIs without any type, format, or content validation.
Passwords Stored in Plaintext
criticalUser passwords stored as raw strings in the database instead of being hashed with a proper algorithm like bcrypt or Argon2.
JWT Without Expiration
highJWTs signed without an `exp` claim that never expire, meaning a stolen token grants permanent access with no way to revoke it.