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 ..).
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.
git ls-files | grep -E '(^|/)\.env($|\.)|(^|/)config($|/)|\.ya?ml$|settings\..*\.py$|application(-.+)?\.(yml|properties)$'
Step 3 — .gitignore check
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 (one regex per line). Execute:
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.
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:
# .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:
### <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 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-repobut 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 ifpwdis 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.pybefore 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/*). NoWriteby 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.