fix(redact-prepush): close the ext-diff, header-lookalike, and ref-parse bypasses

Three ways the pushed diff escaped scanning: (1) a user-level diff.external
or textconv driver replaced the diff with its own output — zero '+' lines,
so the scan saw nothing (now --no-ext-diff --no-textconv); (2) an added
content line whose text begins with "++" renders as "+++…" and the blanket
header skip dropped it (now hunk-aware header detection); (3) a pre-push
ref line that failed to parse was silently skipped, leaving that ref
unscanned (now fails closed with the offending line named).

Minimal reimplementation of the two confirmed bypasses from PR #2498 by
@lubosxyz (the full PR overlaps the chunked-scan work absorbed separately),
plus the unparseable-ref hardening.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-14 20:20:49 -07:00
co-authored by Claude Fable 5
parent 57a211e4b0
commit 888603f570
2 changed files with 67 additions and 6 deletions
+30
View File
@@ -324,3 +324,33 @@ describe("base resolution when the default branch is neither main nor master", (
expect(stderr).toContain("aws.access_key");
});
});
describe("diff-extraction bypasses (#2498, minimal reimplementation)", () => {
test("a diff.external driver cannot blank the scanned diff", () => {
// With diff.external set, plain `git diff` emits the driver's output —
// typically zero '+' lines — so an unhardened scanner reads an empty diff
// and allows a push full of secrets. --no-ext-diff must neutralize it.
const head = commit("leak.txt", "AKIA1234567890ABCDEF\n", "secret behind ext driver");
git(["config", "diff.external", "/usr/bin/true"]);
const { code, stderr } = runHook(`refs/heads/feat ${head} refs/heads/feat ${ZERO}\n`);
git(["config", "--unset", "diff.external"]);
expect(code).toBe(1);
expect(stderr).toContain("aws.access_key");
});
test("an added content line starting with ++ is still scanned", () => {
// Content "++AKIA…" renders in the diff as "+++AKIA…", which a blanket
// startsWith('+++') header skip silently dropped from the scan.
const head = commit("notes.txt", "++AKIA1234567890ABCDEF\n", "content line looks like a header");
const { code, stderr } = runHook(`refs/heads/feat ${head} refs/heads/feat ${ZERO}\n`);
expect(code).toBe(1);
expect(stderr).toContain("aws.access_key");
});
test("an unparseable pre-push ref line fails closed", () => {
commit("ok.txt", "clean\n", "clean commit");
const { code, stderr } = runHook(`refs/heads/feat not-a-sha\n`);
expect(code).toBe(1);
expect(stderr).toContain("could not parse");
});
});