# .env files are gitignored

- **Pattern:** `ab-002565` (`project-snapshot.security.env-files-gitignored`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-25
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002565
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002565)

## Why it matters

A committed `.env` file leaks every credential it contains to anyone with repo read access — and on public GitHub, to automated secret-scanners that crawl new commits within seconds (GitGuardian's 2024 State of Secrets Sprawl report recorded 23.8 million new secrets leaked on GitHub in 2023 alone). Database URLs, Stripe live keys, OAuth client secrets, and third-party API tokens routinely end up in these files. AI coding tools default to creating `.env` alongside `.env.example` when scaffolding, and will happily add the `.env` as a tracked file if the project doesn't already carry a gitignore entry covering it. The majority of "my secrets leaked" incidents on GitHub start exactly here: a single accidental commit, often by a contributor who didn't realize the file wasn't ignored. Once it lands in git history, removing it requires a history rewrite AND rotating every credential the file contained.

## Severity rationale

Critical because a committed `.env` hands over production credentials wholesale — one leaked file typically means rotating every service the project connects to, and public-repo exposure is scraped by attackers in minutes, not days.

## Remediation

Add to `.gitignore`:
  ```
  .env
  .env.local
  .env.development.local
  .env.test.local
  .env.production.local
  ```
  If a `.env` file is already committed, remove it from git history with `git rm --cached .env` and rotate any secrets it contained.

Deeper remediation guidance and cross-reference coverage for this check lives in the `security-hardening` Pro audit — run that after applying this fix for a more exhaustive pass on the same topic.

## Detection

- **ID:** `env-files-gitignored`
- **Severity:** `critical`
- **What to look for:** Read `.gitignore` (or `.git/info/exclude`). Enumerate entries matching env file patterns. Then check whether any actual `.env` / `.env.local` / `.env.production` file is tracked in the working tree.
- **Pass criteria:** `.gitignore` covers at least `.env` and `.env.local` (`.env*` or separate lines), AND no committed `.env*` file exists (only `.env.example` / `.env.sample` may be committed as templates).
- **Fail criteria:** `.gitignore` missing env-file patterns, OR a real `.env` (not `.env.example`) is committed. `.env.example` gitignored alone does NOT count if the real `.env` is not also covered.
- **Skip (N/A) when:** Project is not JS/TS/Python/Ruby/PHP (Go, Rust, Java use different env conventions). Quote the framework detected.
- **Report even on pass:** `"`.gitignore` covers .env, .env.local, .env.production"` — list matched patterns.
- **Detail on fail:** `"`.gitignore` has no .env* entry"` or `"`.env.local` is committed and not in .gitignore"`.
- **Cross-reference:** For rotation playbooks, vault integration, and committed-secret detection, run `security-hardening`.
- **Remediation:** Add to `.gitignore`: `.env`, `.env.local`, `.env.development.local`, `.env.test.local`, `.env.production.local`. If `.env` is already committed: `git rm --cached .env` + rotate any exposed secrets.

Taxons: project-snapshot, cryptography-and-secrets

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