Development record
ahoy manual-guard reads carry a residual Lstat->ReadFile TOCTOU: verifyHookManifest (store.go), and gitignore.go read sites (~72, ~181) each do Lstat+IsRegular+size-cap then a separate os.ReadFile, so a type/symlink swap between check and read is not refused on the same fd. iss-97 converged the six bare-unguarded ahoy reads onto fsutil.ReadGuarded (single-fd O_NOFOLLOW|O_NONBLOCK+cap); these three were left because their structured signals (verifyHookManifest reason strings; gitignore bool flags + the write-path oversize refusal) need preserving, so the convergence is not mechanical. Route them through ReadGuarded too, preserving those signals, to close the TOCTOU and reach one guarded-read mechanism. Sibling of iss-97.
ahoy manual-guard reads carry a residual Lstat->ReadFile TOCTOU: verifyHookManifest (store.go), and gitignore.go read sites (~72, ~181) each do Lstat+IsRegular+size-cap then a separate os.ReadFile, so a type/symlink swap between check and read is not refused on the same fd. iss-97 converged the six bare-unguarded ahoy reads onto fsutil.ReadGuarded (single-fd O_NOFOLLOW|O_NONBLOCK+cap); these three were left because their structured signals (verifyHookManifest reason strings; gitignore bool flags + the write-path oversize refusal) need preserving, so the convergence is not mechanical. Route them through ReadGuarded too, preserving those signals, to close the TOCTOU and reach one guarded-read mechanism. Sibling of iss-97.
Priority (iss-97 security review): the static-plant FIFO-hang and unbounded-read (iss-97's actual severity) are already closed at all three sites by the pre-existing Lstat+IsRegular guard — only the narrower race-window swap remains. Of the three, gitignore.go (72/181) reads cwd/.gitignore, the SAME attacker-influenced boundary as iss-97, so it is the more exposed and should be prioritised; verifyHookManifest reads pluginRoot/hooks/hooks.json (ABCD_PLUGIN_ROOT/executable-dir sourced — the trusted install location, not cwd), a much weaker boundary, so it is lowest priority.
Frontmatter
| id | iss-109 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-109-ahoy-manual-guard-reads-carry-a-residual.md
open on GitHub ↗ · commit history ↗
mentions2
- 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