`gitleaks git` silently reports "no leaks found" with exit 0 when `git log` writes anything to stderr (git-crypt repos affected by default)
Summary
gitleaks git treats any output on git log's stderr as a fatal abort,
then prints 0 commits scanned, no leaks found, and exits 0. This is a
silent false negative: a user running gitleaks git in CI or at the command
line sees a clean report when in fact nothing was scanned.
This is the same class of issue as #1450 (invalid --log-opts) and #1455
(broken repo), but it bites a much broader population: any repository that
uses git-crypt triggers it by default,
with no misconfiguration on the user's part. The git-crypt diff.textconv
filter writes a multi-line Warning: file not encrypted to stderr for every
historical commit that touches a now-encrypted path. That's enough to abort
gitleaks git.
Versions
- gitleaks v8.30.1 (latest as of 2026-05-21)
- git-crypt 0.7.0 (relevant only as a stderr source)
- Reproduced on Windows 11 with Git for Windows 2.x
Reproduction
In any git-crypt repo with at least one encrypted-path commit in history:
gitleaks gitObserved output (truncated):
ERR [git] git-crypt: Warning: file not encrypted
ERR [git] git-crypt: Run 'git-crypt status' to make sure ...
... (repeated per commit) ...
ERR error="stderr is not empty"
INF 0 commits scanned.
INF scanned ~2622506 bytes (2.62 MB) in 2.22s
INF no leaks found
$ echo $?
0Note the 0 commits scanned and the 0 exit code. A user who only reads the
final no leaks found line believes the repo is clean.
Workaround (works, but should not be necessary)
git log -p --all 2>/dev/null | gitleaks stdinThis bypasses gitleaks' internal git log invocation and discards stderr,
producing a real scan (~2.81 MB vs ~2.62 MB on the broken path in our
repo; commits scanned is no longer surfaced because stdin doesn't track
that, but the diff stream is fully consumed).
Suggested fixes (any one would close the silent-false-negative class)
- When
git log -pproduces no commits and stderr is non-empty, exit non-zero (configurable via--exit-codealready, but it isn't honored in this path). - Make
error="stderr is not empty"a hard error by default, with an opt-in--allow-git-stderrflag for users who knowingly run in noisy contexts (git-crypt, hooks, custom textconv filters). - Distinguish "git log spoke to stderr while still streaming commits" (warning) from "git log spoke to stderr and produced zero commits" (fatal).
The current behavior conflates a security-relevant zero-commits-scanned condition with a successful clean scan. Either of the first two options would fix that without breaking the noisy-stderr-but-still-scanning case.
Related issues
- #1450: Invalid
--log-optsdisregards git log exit code and silently does nothing at all - #1455: Scan for broken git repo
This issue is narrower than either of those in that the trigger is a common, non-broken configuration (git-crypt is widely used for repo-versioned secrets), but the underlying defect is the same: stderr-driven abort + exit 0
- "no leaks found".
Why this matters
git-crypt is one of the standard answers to "how do I version-control secrets
in a private repo?" Running gitleaks git on such a repo is a routine
defense-in-depth step. A silent false negative here is exactly the
threat model gitleaks exists to defend against.
Source: gitleaks/gitleaks