# Auditing Env Files

> Audits a project directory for leaked secrets, mis-handled .env files, committed credentials, and hardcoded API keys before a release or open-source publish. Use when the user asks to "audit env files", "check for leaked secrets", "prep this repo for open source", "review before rotation", or mentions .env exposure, gitignore safety, or pre-publish security checks. Covers .gitignore verification, .env vs .env.example diffing, source-code secret scanning with a fixed pattern set, git history search, and a human-readable rotation plan with masked values. Do NOT use for live cloud credential rotation, cloud IAM review, runtime secret management (Vault, AWS Secrets Manager), or dependency vulnerability scanning.

- Skill: `criseulises/auditing-env-files` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add criseulises/auditing-env-files`
- Raw SKILL.md: https://api.skillmd.com/api/skills/criseulises/auditing-env-files/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: criseulises (https://skillmd.com/u/criseulises)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/criseulises/auditing-env-files

---


# Auditing Env Files

## Overview

This skill performs a read-only security audit of the current working directory to
surface leaked secrets before the user opens the repo, rotates keys, or ships a
release. It runs a deterministic checklist over tracked files and git history,
masks every secret it reports, and produces a prioritized report plus a rotation
plan. It never executes destructive operations and never reaches the network.

## Quick reference

| Task | Approach |
|---|---|
| Confirm scope | `git rev-parse --show-toplevel` — must match `pwd` |
| .gitignore coverage | `git check-ignore -v .env .env.local .env.*` |
| .env vs .env.example diff | `scripts/compare_env.py .env .env.example` |
| Source scan (live patterns) | `git grep -nE "$(cat reference/patterns.txt)"` |
| History scan | `git log --all -p -S'<secret-fragment>'` |
| Mask a value | `scripts/mask.py <value>` → `AKIA****3X7Q` |
| Write report | After user confirmation, `./.env-audit-report.md` |

## Workflow

Copy this checklist and check off items as you complete them:

```
Audit Progress:
- [ ] Step 1: Confirm scope (current directory is a git repo, working tree is clean)
- [ ] Step 2: File inventory (list .env*, config files, anything that might hold keys)
- [ ] Step 3: .gitignore check (every .env file must be ignored or tracked-on-purpose)
- [ ] Step 4: Diff .env vs .env.example and flag realistic-looking values in .example
- [ ] Step 5: Source-code scan against reference/patterns.txt
- [ ] Step 6: Git history scan for each distinct finding
- [ ] Step 7: Build the report, mask every value, rank severities
- [ ] Step 8: Ask the user to confirm before writing report to disk
- [ ] Step 9: Produce rotation plan with provider + procedure per finding
```

### Step 1 — Confirm scope

Verify you are at the root of a git repository. Refuse any argument that escapes the
current working directory (starts with `/`, `~`, or contains `..`).

```bash
git rev-parse --show-toplevel
```

If the output does not match the current working directory, stop and ask the user
to `cd` to the project root.

### Step 2 — File inventory

Enumerate files that commonly hold secrets. Do not read their contents yet.

```bash
git ls-files | grep -E '(^|/)\.env($|\.)|(^|/)config($|/)|\.ya?ml$|settings\..*\.py$|application(-.+)?\.(yml|properties)$'
```

### Step 3 — .gitignore check

```bash
git check-ignore -v .env .env.local .env.development .env.production 2>&1
```

A file that is **tracked** AND named `.env*` (except `.env.example`, `.env.sample`)
is always at least **High** severity. If `.env` is not ignored and not tracked,
flag that the project is one mistake away from a leak.

### Step 4 — .env vs .env.example diff

Read both files. For each key in `.env.example`, verify the value looks like a
placeholder. Run every candidate through the detector:

- Placeholder if: matches `your-[a-z-]+-here`, `REPLACE_ME`, `xxxx+`, `example`,
  is empty, or equals the key name.
- Real-looking otherwise — flag the line at **High**.

### Step 5 — Source-code scan

Use `git grep` over tracked files only. The full pattern list lives in
[reference/patterns.txt](reference/patterns.txt) (one regex per line). Execute:

```bash
python scripts/scan.py
```

The script wraps `git grep -nE` and emits JSON with `{file, line, pattern_name,
masked_value, severity}`.

### Step 6 — Git history scan

For each distinct finding, search the full history. If the same masked value
appears in a prior commit, record the commit SHAs.

```bash
git log --all -p -S"<first-4-chars-of-value>" -- <file>
```

Do not search for the full secret (that would re-log it to terminal history).

### Step 7 — Build the report

Use this exact structure:

```markdown
# .env audit — <repo name> — <ISO date>

## Summary
- Critical: N
- High: N
- Medium: N
- Info: N

## Critical
- <file>:<line> — <pattern_name> — value: `AKIA****3X7Q` — context: <one line>
- ...

## High
...

## Medium
...

## Info
...

## Git history findings
- <commit-sha> — <file> — <pattern_name> — first seen <date>

## Rotation plan
See below.
```

### Step 8 — User confirmation before writing

Show the report in chat. Then ask:

> "¿Querés que guarde el reporte en `./.env-audit-report.md`? (y/N)"

Only write on explicit `y` / `yes` / `sí`. Never overwrite a pre-existing file
without a second confirmation.

### Step 9 — Rotation plan

For each distinct credential, produce:

```markdown
### <pattern_name> in <file>
- Provider: <AWS IAM | Stripe | GitHub | generic>
- Rotation doc: link to the provider's current rotation docs
- Action: list specific steps (issue new, rollover, revoke old, verify)
- CLI (if applicable): the exact command the user runs locally
- Blast-radius notes: which systems use this key; coordinate if shared
```

## Patterns scanned

See [reference/patterns.txt](reference/patterns.txt) for the full list. Summary:

- AWS access key: `AKIA[0-9A-Z]{16}`
- Stripe live secret: `sk_live_[0-9a-zA-Z]{24}`
- GitHub PAT: `gh[pousr]_[0-9a-zA-Z]{36}`
- Slack token: `xox[baprs]-[0-9a-zA-Z-]{10,}`
- Google API key: `AIza[0-9A-Za-z_-]{35}`
- Generic "secret/token/api_key = \"...\"": `(?i)(api[_-]?key|secret|token|password)\s*[:=]\s*['"][^'"]{12,}`
- JWT header: `eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+`

## Report format

Always write the report in Markdown with the exact headings from Step 7. Severities
MUST use the buckets Critical / High / Medium / Info. Every secret MUST be masked
with `scripts/mask.py` (first 4 + last 4 chars, middle replaced by `****`).

## Non-goals

- No live cloud credential rotation. The skill produces a plan; the user executes it.
- No cloud IAM review.
- No penetration testing or dynamic analysis.
- No dependency CVE scanning (use a separate skill).
- No git history rewriting. The skill explains the risk and references `git filter-repo`
  but never runs it.
- No MITRE ATT&CK mapping.

## Security

- **Scope**: operates only within the current git working tree. Refuses paths with
  `..`, `~`, or absolute prefixes. Refuses if `pwd` is not inside a git repo.
- **No silent network calls**. Zero outbound requests. The rotation plan is a text
  document the user executes manually.
- **No home-dir reads**. Never touches `~/.ssh/`, `~/.aws/`, `~/.kube/`, the system
  keychain, `HISTFILE`, shell rc files, or browser profiles.
- **No full secret logging**. Every value is passed through `scripts/mask.py` before
  appearing anywhere.
- **Write-on-confirm**. The only file the skill creates is `./.env-audit-report.md`,
  and only after explicit user confirmation.
- **Least-privilege `allowed-tools`**: `Read`, `Grep`, `Glob`, `Bash(git *)`,
  `Bash(python scripts/*)`. No `Write` by default; the confirmation flow enables it.
- **No destructive actions**. Never modifies tracked files, never runs
  `git filter-repo`, never force-pushes.
- **Dependencies**: Python 3.10+ standard library only. No pip installs.

