fix(agents-runtime): realpath guard read/write/edit against symlink escape#4360
fix(agents-runtime): realpath guard read/write/edit against symlink escape#4360msfstef wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4360 +/- ##
==========================================
+ Coverage 55.84% 55.87% +0.02%
==========================================
Files 245 246 +1
Lines 24847 24878 +31
Branches 6878 6887 +9
==========================================
+ Hits 13876 13900 +24
- Misses 10957 10964 +7
Partials 14 14
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
383e8ab to
5a2e847
Compare
Claude Code ReviewSummaryIncremental review. Iteration 2 addresses the ENOTDIR suggestion from iteration 1; the implementation now walks past regular-file ancestors instead of surfacing an opaque tool error, with a dedicated test. No regressions, no new issues. Recommending merge. What's Working Well
Issues FoundCritical (Must Fix)None. Important (Should Fix)None. Suggestions (Nice to Have)Carried over from iteration 1, all explicitly low-priority — none block merge. Listing for completeness:
Issue ConformanceStill no linked GitHub issue. The PR description references `plans/sandboxing-investigation.md §1.3 and §3.5` — that file is not in the repo at the time of this review (only `plans/DeployStarter.md` exists at the root). Same minor traceability gap noted previously; not a code issue. Implementation continues to match the PR description and changeset: realpath guard on read/write/edit, intra-workspace symlinks preserved, hardlink gap acknowledged, predictable error string. Previous Review Status
Review iteration: 2 | 2026-05-19 |
…scape The pre-existing cwd guard in `read-file.ts`, `write.ts`, and `edit.ts` was a string prefix check on the resolved-but-not-realpathed path. A symlink inside the working directory pointing outside was followed transparently — CVE-2025-53109/53110 class bypass. The characterization tests added in #4354 documented this behavior; this PR flips them to asserting the bypass is now blocked, and adds positive tests for intra-workspace symlinks (pnpm `.pnpm` trees, etc.) which keep working. For non-existent write/edit targets, `realpath` is called on the deepest existing ancestor and containment is checked from there — the file's final name has no bearing on the parent's real path. Known gap, documented in `path-guard.ts`: hardlinks across the cwd boundary share the inode but report a path inside cwd, so the realpath check passes them. A proper fix requires a sandbox; see plans/sandboxing-investigation.md §3.3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5a2e847 to
9cb21c7
Compare
Summary
Closes the symlink-bypass class of the
read/write/editpath guard (CVE-2025-53109/53110 class). Previously the cwd check was a string prefix on the un-resolved path, so a symlink at<cwd>/link.txtpointing to/etc/hostnamewas readable, and a symlinked directory could redirect writes outside the workspace. The guard now realpaths the resolved target (or its deepest existing ancestor for write/edit creating new files) and re-checks containment.The prefix check and realpath check live together in a single
resolveInsideWorkdir(filePath, workingDirectory)helper used by all three tools. Returns{ ok: true, resolved }or{ ok: false, reason }; each tool calls it once.See
plans/sandboxing-investigation.md§1.3 and §3.5.Known gap
Hardlinks across the cwd boundary share the inode but report a path inside cwd, so the realpath check passes them. A proper fix requires a sandbox (§3.3 of the design doc).
Risk
Low. Could surface in setups that intentionally symlink the workspace out to a parent monorepo. Predictable error message: "Path X resolves outside the working directory via a symlink".
Test plan
test/path-guard.test.ts— 10 unit tests covering the helper directly: in-bounds existent/non-existent,..and absolute-path escape, file/directory symlinks pointing outside, intra-cwd file/directory symlinks, regular-file ancestor (ENOTDIR walk-up), workspace-itself-is-a-symlinktest/tool-path-symlink.test.ts— 3 integration tests proving read/write/edit honor the guard at the tool boundarypnpm test,pnpm typecheck,pnpm stylecheckclean inagents-runtimeAddressed from review
existing-file.txt/sub/new.txtproduces the natural domain error rather than re-throwing the kernel code through the outer catch.🤖 Generated with Claude Code