Catch secrets split across lines in UTF-16 files and stop deleted binaries from blocking pushes (GST-2261) (#4261)

* Catch secrets split across lines in UTF-16 files and skip deleted files in the push scan (GST-2261)

Each reading of a file git calls binary is now scanned as its own text with the file's line numbers, so a keyword and its value on the next line stay neighbours. The pre-push hook diffs with --irreversible-delete, so a deleted binary's old bytes no longer fill its 64 MiB buffer.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Leave the landed binary-scan changelog fragment unchanged (GST-2261)

Review-Finding: changelog.d/scan-binary-files-for-secrets.md:1:release reader=core
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* List a token once when several readings of a binary file find it (GST-2261)

Review-Finding: p1/specialist-batched#1 reader=specialist-batched
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Report a repeated token once only within one binary file, so an allowlisted token never hides another (GST-2261)

Review-Finding: p2/specialist-batched#1 reader=security
Review-Finding: p2/red-team#2 reader=red-team
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Name the changelog fragment after the branch (GST-2261)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Keep the side-by-side reading of binary files so a key and its keyword in different readings still fail (GST-2261)

Review-Finding: audit/cross-family#1 reader=gpt-6.1-sol
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-11-10 02:12:29 +00:00
1 parent 46d51496b4
commit ccc3f0fc14
6 files changed
+148 -37

No files matched your search

+12 -6
View File
@@ -220,13 +220,19 @@ Two stages with separate clocks, both printed:
file is read whole from disk. A file over the size limit, or whose full diff
does not parse, is scanned on its added lines alone, without that context.
A file git calls binary (a NUL byte, UTF-16 text, or a `-diff` attribute)
is still scanned: the diff runs with `--text`, and each added line is read
is still scanned: the diff runs with `--text`, and its added lines are read
three ways, as bytes with control runs turned into spaces and as little- and
big-endian UTF-16. Only credential findings count in such a file, so image
bytes that look like a phone number are not reported. A file whose scanned
text is over the scanner's 16 MiB limit fails the check, and the pre-push
hook blocks a push whose diff is over 64 MiB; keep large binaries in Git LFS,
whose small pointer files scan as text. A merge-base diff git does not finish
big-endian UTF-16. The three readings are scanned side by side on each line,
so a keyword in one reading still meets its value in another, and each
reading is also scanned as its own text with the file's line numbers, so a keyword and its value on the next line (an AWS secret key
under its YAML key) are caught in UTF-16 text as in plain text. Only
credential findings count in such a file, so image bytes that look like a
phone number are not reported. A file whose scanned text is over the
scanner's 16 MiB limit fails the check, and the pre-push hook blocks a push
whose diff is over 64 MiB. The hook leaves deleted files out of that diff,
so removing a large binary does not count toward the limit, but a replaced
binary's old bytes still do. Keep large binaries in Git LFS, whose small
pointer files scan as text. A merge-base diff git does not finish
(an error, a kill or a full buffer) is `PREGATE_ENVIRONMENT`, never a pass.
The pass line names the files read: `12 added lines clean in 3 files (1 binary)`.
- `strays`: a new file at the repository root, a new top-level directory, or a