# .env files in .gitignore with no git history

- **Pattern:** `ab-001257` (`environment-security.secrets-management.env-gitignore`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001257
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001257)

## Why it matters

A .env file committed to git — even once, even years ago — permanently exposes every secret it contained. Git history is not cleared by deleting the file from the working tree. Attackers who clone your repo, access a GitHub fork, or pull a leaked archive get your database passwords, API keys, and OAuth secrets instantly. OWASP A05 (Security Misconfiguration) and NIST SC-28 both flag unprotected sensitive data at rest. The blast radius is immediate: a single committed production .env means every secret in it is compromised and must be rotated before you do anything else.

## Severity rationale

Critical because a committed .env file permanently exposes production credentials to anyone with repository access, making secret rotation mandatory regardless of when the commit occurred.

## Remediation

Add .env patterns to `.gitignore` before any secrets are committed. If a .env file already exists in git history, treat every secret it contained as compromised and rotate them immediately — removing the file from the working tree does not remove it from history.

```gitignore
# .gitignore
.env
.env.local
.env.*.local
.env.production
.env.staging
.env.development
```

To scrub the file from history, run `git filter-repo --path .env.production --invert-paths` (preferred over `filter-branch`). After history rewrite, force-push all branches and notify all collaborators to re-clone.

## Detection

- **ID:** `env-gitignore`
- **Severity:** `critical`
- **What to look for:** Check `.gitignore` for patterns that exclude .env files. Look for entries like `.env`, `.env.local`, `.env.*.local`, `*.env`, or wildcard patterns that catch environment files. Then check git history using `git log -p -- '.env*'` to confirm no .env files have been committed.
- **Pass criteria:** Count all `.env*` patterns in `.gitignore`. `.gitignore` explicitly lists at least 1 `.env*` or equivalent pattern. Git history shows no commits containing .env files (or only on branches that were never merged to production). Do not pass when `.env` files appear in `git log -p -- '.env*'` output even if they were later deleted.
- **Fail criteria:** `.env` files are not listed in `.gitignore`, OR git history shows .env files were committed (even if later deleted, the credentials are still in git history and compromised). Quote the git log entry showing the committed file.
- **Cross-reference:** For hardcoded secrets in source code rather than .env files, see the `no-hardcoded-secrets` check below.
- **Skip (N/A) when:** Never — environment files should always be gitignored.
- **Detail on fail:** Specify which files were found or committed. Example: `".env and .env.local not in .gitignore"` or `"`.env.production was committed 3 commits ago; credentials may be compromised even if file is now deleted from working directory"`.
- **Remediation:** Add .env files to `.gitignore` immediately:

  ```
  .env
  .env.local
  .env.*.local
  .env.production
  .env.staging
  .env.development
  ```

  If .env files have been committed, they are compromised — rotate all secrets in that file. To remove them from git history (not just the working directory), use `git filter-branch` or `git filter-repo`. This is a one-time remediation for each compromised file.

## External references

- cwe CWE-538
- cwe CWE-312
- owasp A05
- nist SC-28

Taxons: cryptography-and-secrets, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-001257
