Development record
scanner.New reads the per-repo .abcd/config/pii.json override with a bare os.ReadFile — no O_NOFOLLOW, no size cap, no regular-file check — unlike every sibling trust-boundary config reader in this codebase (guard.Load, rules.Load, banlist private store) which goes through fsutil.ReadGuarded; a FIFO planted at that path hangs the read forever and a symlink to a device file (git-committable, mode 120000, no local write access needed) grows the read unbounded toward OOM; reachable automatically via the SessionEnd hook's history capture, which also holds an unbounded history.repoLock flock across the hang, permanently wedging transcript capture for that repo; this is the same bug class already fixed once for ahoy.Detect under iss-97. Independently verified: FIFO hangs past 3s deadline (control: no-config-file case returns in 0.01s), /dev/zero symlink accumulates ~137 MiB/s, causal fix test (swap to fsutil.ReadGuarded) confirmed both cases resolve
scanner.New reads the per-repo .abcd/config/pii.json override with a bare os.ReadFile — no O_NOFOLLOW, no size cap, no regular-file check — unlike every sibling trust-boundary config reader in this codebase (guard.Load, rules.Load, banlist private store) which goes through fsutil.ReadGuarded; a FIFO planted at that path hangs the read forever and a symlink to a device file (git-committable, mode 120000, no local write access needed) grows the read unbounded toward OOM; reachable automatically via the SessionEnd hook's history capture, which also holds an unbounded history.repoLock flock across the hang, permanently wedging transcript capture for that repo; this is the same bug class already fixed once for ahoy.Detect under iss-97. Independently verified: FIFO hangs past 3s deadline (control: no-config-file case returns in 0.01s), /dev/zero symlink accumulates ~137 MiB/s, causal fix test (swap to fsutil.ReadGuarded) confirmed both cases resolve
Frontmatter
| id | iss-202 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | critical |
.abcd/work/issues/resolved/iss-202-scanner-pii-config-unguarded-read.md
open on GitHub ↗ · commit history ↗
mentions6
- dcn-26080800000000022026-08-08 — bug-hunt loop round 9 (state issue #197): a multi-angle sweep (5
- iss-97ahoy.Detect reads CLAUDE.md/AGENTS.md/config via plain os.ReadFile with no size cap or O_NONBLOCK, unlike the hardened session-end transcript read; a FIFO or multi-GB file at cwd could hang or slurp any hook that calls Detect (session-start, session-end, ahoy verbs). Harden Detect's marker/config reads to match maxTranscriptBytes plus a non-blocking open.
- iss-310memory ingest materialFromLocal reads a user-typed operand with Stat-then-ReadFile leaving a swap window and an uncapped-growth read
- iss-383the history transcript store's read path is unguarded — listRecords and Read use raw os.ReadFile, so a planted FIFO wedges history list and history capture while the store flock is held, and a symlinked record is followed
- iss-2608241612007530the issue-resolution gate is triggered by the trailer, so a fix that lands without one is invisible to it. RS001 fires only on a commit carrying a Resolves trailer, and RS002/RS003 only on stamps that already exist, so a merged fix whose commit names no issue passes all three rules and leaves its record in open/ — the exact backlog iss-2608241347321757 was built to stop, reached from the other direction. Measured 2026-08-24: 1315 commits name an iss- id somewhere in the message and 3 carry the trailer. iss-202 is the standing instance: its fix merged on 2026-08-24 in a commit ending with a bare 'iss-202' line rather than the trailer form, and its record sits in open/ with the fix shipped. The missing detector is the inverse direction — a change touching code an open record describes, declaring no resolution.
- the-record-lands-with-the-actThe record lands with the act