You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
gstack-redact-prepush: no allowlist plumbing (engine supports it) + unchunked scan fail-closes on >1 MiB diffs — both push users onto GSTACK_REDACT_PREPUSH=skip, which skips all scanning #2304
Two defects in bin/gstack-redact-prepush (observed on gstack 1.60.1.0, macOS, bun) that together train users to reach for GSTACK_REDACT_PREPUSH=skip — and that valve skips ALL scanning, which defeats the guard exactly when it matters. Related but distinct from #1946 (fail-open on git errors, which the current hook already fixes with gitStrict).
Defect 1 — the hook never passes the engine's allowlist option, so synthetic fixtures hard-block pushes
exportinterfaceScanOptions{/** Extra allowlist entries (exact strings) that suppress a matched span. */allowlist?: string[];
...
}
…but the hook calls scan(added, { repoVisibility: "private" }) with no allowlist and no way for a repo to provide one. Any repo whose committed docker-compose / test files contain a synthetic DB URL like postgresql://booking:booking@localhost:5432/booking gets a HIGH db.url_with_password on every push that touches those lines (the booking:booking password is not caught by isPlaceholderSpan). There is no remediation path other than the skip valve, so the valve becomes routine — we counted the skip in 14 of 38 working transcripts in one project before intervening.
Suggested fix: read an optional repo-level allowlist file (e.g. .gstack-redact-allowlist at the repo root — one literal span per line, # comments) and pass it through to scan(). Value-exact spans only; the engine already does allow.has(span) so no engine change is needed.
Defect 2 — added lines are scanned as ONE string, so >1 MiB diffs fail closed with engine.input_too_large, and the only relief valve disables scanning entirely
The engine's 1 MiB maxBytes fail-closed cap is correct for a single scan call, but the hook concatenates all added lines per ref and scans once. Feature-branch pushes with big lockfiles/docs/generated files routinely exceed 1 MiB, producing:
HIGH engine.input_too_large Input too large to scan safely (N > 1048576 bytes) — blocking fail-closed
The push is blocked on SIZE, not on a finding — and the documented escape (GSTACK_REDACT_PREPUSH=skip) then performs zero scanning on exactly the largest, riskiest pushes.
Suggested fix: chunk the added-lines text on line boundaries under maxBytes (a single line larger than the chunk size can be sliced with a few KB of overlap so a token spanning the cut is still seen whole), scan each chunk, and aggregate findings. In our downstream copy of this approach, a 3.96 MB added-lines diff scans in 6 chunks in ~340 ms, and a single planted credential inside such a diff is still caught.
Why filing instead of patching
We run the fix as a repo-local pre-push.local leg (same engine, allowlist + chunking + fail-closed watchdog) because hand-editing the managed binary gets clobbered by upgrades. Happy to share the implementation if useful.
Activity
v1.64.0.0 fix wave: full tracker audit — 90 fixes, 52 issues closed, …