The tracked-.env check.
A committed .env is a leak by itself, whatever it contains. Git history keeps every value it ever held, and every clone gets a copy.
What the check reads
The check asks git for every tracked file and keeps the ones whose name is .env or starts with .env., leaving out templates like .env.example, .env.sample, .env.template and .env.dist. Any tracked .env fails the run, and the record names each file, up to ten of them. If none is tracked, the check then looks at local files git does not ignore: a local .env that is not gitignored produces a warning instead, because it is one git add away from being committed. Gitignored .env files are never read at all.
Why AI-built code ships this
AI project templates read configuration from .env, and the very first git add an agent runs commits that file along with everything else. The app works, the diff looks harmless, and the keys are now part of git history, where deleting the file later does not delete the values it held. This is the single most common leak in AI-built repos, and it happens before anyone thinks of it as a secret.
Why it blocks
Blocks. A tracked .env is a NO-GO regardless of its contents, because git history keeps every value it ever held: remove the file from git, add it to .gitignore, and rotate every key it ever contained. A local .env that exists but is not gitignored warns rather than blocks, since nothing has been committed yet, and the record names it so it gets ignored before the next add.
In the proof record
A pass line when no .env is tracked, a warning naming local .env files that are not gitignored, or a fail naming each tracked .env plus the removal and rotation steps.
✓ Tracked .env file — No .env files tracked by git (gitignored local .env files are fine and are never read). ⚠ Tracked .env file — 1 local .env file(s) are NOT gitignored — one 'git add .' away from committing your keys. ✗ Tracked .env file — 1 .env file(s) tracked by git — a committed .env is a leak by itself, whatever it contains.
Honest limits
It matches .env file names, nothing else: a secret sitting in a file named differently, a config.json for example, is invisible here and is the secret scan's job to catch. It sees the current tree, not history, so values buried in old commits are out of reach, which is exactly why rotation is part of the fix. And a template file that holds real values passes this check by name, though its contents still run through the secret scan.
Want every change gated like this before it ships?
The same gate runs in every engagement, and each piece of work ends on a plain go or no-go, in writing. The gate itself is open source, so you can read exactly what we run.
The other 6 gates
The whole method, from the controlled zone to the proof record: the methodology.