Your .env.local is not a vulnerability
We shipped a check that reported a correctly-gitignored .env.local as a critical committed secret. It fired on almost every healthy repo. Here’s what went wrong.
While wiring our repository scanner into an MCP server, we pointed it at our own codebase. It returned a CRITICAL:
[CRITICAL] Committed environment file: .env.local .env.local is tracked in the repo and contains key=value pairs. fix: Remove .env.local from git, add it to .gitignore…
The file was gitignored. It had never been committed. The proof text asserted a fact about git that the check had never verified, it had only looked at the filename.
function isCommittedEnv(path: string): boolean {
const name = path.split("/").pop() || "";
if (!name.startsWith(".env")) return false;
return !/\.(example|sample|template)$/i.test(name);
}Why this one is worse than an ordinary false positive
A gitignored .env.local isn’t an edge case. It’s the correct setup, present in essentially every well-configured project. This check fired on the good state.
It was also our loudest severity, with remediation advice telling people to run git rm --cached on a file git had never heard of. And it surfaced through an MCP server, where an agent would act on it without a human ever reading the reasoning.
A check that asserts a fact has to verify that fact. “Tracked in the repo” is a claim about git, so the only acceptable source for it is git.
Four states, not one
An env file on disk can mean four different things, and only one of them is an emergency:
- Tracked by git → critical. Real leak, and it survives in history after deletion.
- Untracked and gitignored → no finding at all. This is the correct configuration.
- Untracked but not ignored → medium. One git add . away from becoming the first case.
- Not a git repo, or git unavailable → medium, with the proof saying plainly that tracking could not be determined.
Implementing that meant asking git ls-files what it actually tracks and git check-ignore whether a path is deliberately excluded, then grading on the answer.
The general rule
This is the same principle behind verifying leaked keys against their issuer rather than trusting a regex. Two instances of one rule: when a finding makes a claim, check the claim, and when you can’t check it, say so in the finding instead of asserting it anyway.
False positives don’t just waste time. They teach people that the alert means nothing, and that lesson sticks around for the alert that mattered.
Written by the Flare.ai team.