fix(paths): keep IsSubpath case-sensitive; fold only for exclusion

main

Commit

pjbgf2mo ago

Review found that making the shared IsSubpath case-insensitive on Windows/macOS weakened fail-closed containment gates. IsSubpath is used both for protected-path EXCLUSION and for allow/containment checks (rewind.legacyFallbackTranscriptPath, utils.openAllowedRoot). Folding is safe only for exclusion (over-match => over-exclude); for a fail-closed gate it fails open. On a case-sensitive volume under GOOS=darwin, a crafted .Entire/metadata trailer would pass containment yet resolve to a different on-disk directory than the strict check intended.

Revert IsSubpath to case-sensitive (the correct primitive for containment) and add IsProtectedSubpath, which applies the OS-based case fold and is documented as exclusion-only. Route the exclusion callers through it (IsInfrastructurePath, the protected-dir loops in state.go/ephemeral.go/common.go); leave the rewind/utils containment gates on strict IsSubpath.

Tests: IsSubpath is asserted case-sensitive on all OSes; folding moves to IsProtectedSubpath; add a legacyFallbackTranscriptPath case proving a case-variant metadata dir fails closed on every platform.

Assisted-by: Claude Opus 4.8 noreply@anthropic.com Signed-off-by: Paulo Gomes paulo@entire.io Entire-Checkpoint: 01KXK5A53886X5ZEZHQFPGBEJ0

Checkpoints

Review Linear Issues and Security Fixes

Claude CodeOpus 4.8[1m]
View session
Checkpoint 1