Summary
MCP validates a lexical/canonical index path, then reopens it later for traversal, allowing a local symlink swap after authorization.
v1.38.0 evidence / reproduction / control flow
McpToolHandlers.Indexing.cs:32-49 performs GetFullPath, containment/root checks, and Directory.Exists. Indexing later resolves the path again. McpPathBoundary.cs:63-100 establishes containment only at check time, not for the directory identity traversed.
Impact
A race can redirect a network-triggered index outside the client-approved roots, exposing filenames/content to indexing and downstream query surfaces.
Suggested direction / acceptance criteria
- Open a no-follow directory handle during authorization and traverse relative to that identity, or revalidate canonical containment for every opened entry.
- Reject link/identity changes between authorization and scan.
- Preserve the checked root identity in audit output.
- Add a deterministic swap-race test using a controllable filesystem seam.
Dogfooding candidate IDs: M067.
Observed with locally built cdidx v1.38.0 from origin/main on 2026-07-15.
Summary
MCP validates a lexical/canonical index path, then reopens it later for traversal, allowing a local symlink swap after authorization.
v1.38.0 evidence / reproduction / control flow
McpToolHandlers.Indexing.cs:32-49performsGetFullPath, containment/root checks, andDirectory.Exists. Indexing later resolves the path again.McpPathBoundary.cs:63-100establishes containment only at check time, not for the directory identity traversed.Impact
A race can redirect a network-triggered index outside the client-approved roots, exposing filenames/content to indexing and downstream query surfaces.
Suggested direction / acceptance criteria
Dogfooding candidate IDs: M067.
Observed with locally built cdidx v1.38.0 from origin/main on 2026-07-15.