Skip to content

fix(web): open file links that climb out of the workspace - #16754

Closed
macodev00 wants to merge 1 commit into
pingdotgg:mainfrom
macodev00:cursor/file-link-dotdot-outside-e9a2
Closed

macodev00 wants to merge 1 commit into
pingdotgg:mainfrom
macodev00:cursor/file-link-dotdot-outside-e9a2

Conversation

@macodev00

Copy link
Copy Markdown
Contributor

What Changed

resolvePathLinkTarget now collapses . and .. lexically on the path only, after ~/ expansion and before the workspace-membership check. A :line or :line:column suffix is preserved. Absolute markdown links go through the same collapse, so /repo/../other/notes.md is not classified as a file inside /repo.

An in-workspace link such as docs/guide/../readme.md stays a workspace file. .. does not climb above a POSIX root, a Windows drive root, or a UNC share. The server still rejects a relative path that escapes the workspace. apps/mobile is unchanged.

Why

A markdown or inline link like [notes.md](../other/notes.md) was joined onto the workspace root and left .. in the string. workspaceRelativeFilePath only checks that the string starts with the root, so /home/me/project/../other/notes.md became the workspace-relative path ../other/notes.md. The server rejects that path, and the file viewer fails instead of opening the sibling file read-only the way an absolute or ~/ link already does.

Fixes #16354

Verification

Base: upstream/main 0f4f02abb6ab5428c06a7e4b6c76b3ec84c62498 (merges cleanly with current main)
Head: b40dfe4099d4a4da61d0ca9d354673df6f2b7641
Platform: Linux 6.12.94+ x86_64, Node v24.13.1 (Vite+ runtime and capture server on Node v24.21.0).

  • vp test run apps/web/src/terminal-links.test.ts apps/web/src/markdown-links.test.ts — 2 files passed, 94 tests passed.
  • vp run --filter @t3tools/web typecheck — exit 0 (tsc --noEmit).
  • vp run --filter @t3tools/web test — 457 files passed, 6146 tests passed.
  • vp check — 0 errors and 893 warnings in 4848 files.
  • vp run knip:check — exit 0.

Manual check: a throwaway repo at /tmp/fx/project contains links.md with [notes.md](../other/notes.md) and [readme.md](docs/guide/../readme.md). The target file is /tmp/fx/other/notes.md, outside the project. links.md was opened in the Files panel's rendered markdown preview, the notes.md chip was hovered, then clicked.

On main, the tooltip is /tmp/fx/project/../other/notes.md and the breadcrumbs are project > .. > other > notes.md. The click does not open the file; the panel shows "The requested path is outside the workspace" for workspace /tmp/fx/project.

On this branch, the tooltip is /tmp/fx/other/notes.md and the breadcrumbs are tmp > fx > other > notes.md. The click opens the sibling file read-only and shows SIBLING_NOTES_OUTSIDE_WORKSPACE.

Limitations: the collapse is lexical and does not follow symlinks. The server still rejects a relative path that escapes the workspace. Mobile's resolver was not changed.

UI Changes

Before After
before: rendered links after: rendered links
before: chip tooltip after: chip tooltip
before: click result after: click result
before recording after recording
before.mp4 after.mp4

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

A relative link joined onto the workspace root kept its .. segments, so the
prefix check treated it as a workspace file and the server rejected it.
Collapse . and .. lexically on the path, after ~/ expansion and before that
check, while keeping any line or column suffix.
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 7, 2026
};
}

if (path.startsWith("/")) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High src/terminal-links.ts:304

For a forward-slash UNC link such as //server/share/dir/../file.md, this branch treats // as a POSIX root and returns /server/share/file.md; on Windows, the viewer therefore targets the local drive path instead of the network share. Recognize the //server/share prefix as a UNC root before the POSIX-root branch so collapsing preserves both leading separators.

+  const forwardSlashUnc = /^\/\/[^/]+\/[^/]+/.exec(path);
+  if (forwardSlashUnc?.[0]) {
+    return {
+      prefix: forwardSlashUnc[0],
+      separator: "/",
+      rooted: true,
+      segments: path.slice(forwardSlashUnc[0].length).split(/[\\/]/),
+      trailingSeparator,
+    };
+  }
+
   if (path.startsWith("/")) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/terminal-links.ts around line 304:

For a forward-slash UNC link such as `//server/share/dir/../file.md`, this branch treats `//` as a POSIX root and returns `/server/share/file.md`; on Windows, the viewer therefore targets the local drive path instead of the network share. Recognize the `//server/share` prefix as a UNC root before the POSIX-root branch so collapsing preserves both leading separators.

@macroscopeapp

macroscopeapp Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR changes shared file-link resolution across terminal, markdown, preview, Git, and file-manager flows by adding substantial cross-platform path normalization. An unresolved High-severity finding shows that forward-slash UNC paths can still be rewritten to local POSIX paths, requiring human review.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ac750f7c-44d8-4f4a-ac78-77b3a75aa835
📥 Commits

Reviewing files that changed from the base of the PR and between 4b063a0 and b40dfe4.

📒 Files selected for processing (4)
  • apps/web/src/markdown-links.test.ts
  • apps/web/src/markdown-links.ts
  • apps/web/src/terminal-links.test.ts
  • apps/web/src/terminal-links.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Path resolution now collapses . and .. segments before workspace classification. Markdown absolute paths use the shared resolver. Tests cover workspace boundaries, home expansion, root handling, and preservation of line and column suffixes.

Changes

File Link Path Resolution

Layer / File(s) Summary
Normalize resolved paths
apps/web/src/terminal-links.ts, apps/web/src/terminal-links.test.ts
resolvePathLinkTarget collapses dot segments and preserves line and column suffixes. Parent segments cannot climb above POSIX roots, Windows drive roots, or UNC shares. Tests cover relative and absolute paths and home expansion.
Resolve markdown file links
apps/web/src/markdown-links.ts, apps/web/src/markdown-links.test.ts
Absolute markdown paths now use resolvePathLinkTarget. Tests verify normalized paths and workspace-relative metadata for paths inside and outside the workspace.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to b40df

File links appear to resolve as intended, with no confirmed issue requiring a fix before merge.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to b40df

Sibling-file links now reach the same authorized, read-only file-opening behavior already available through absolute links. The reviewed change does not grant additional filesystem permissions or weaken workspace-relative path checks.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The existing absolute-read capability reaches host files outside the workspace in the selected server environment, subject to session read scope, server-process filesystem permissions, and file-read restrictions. The PR broadens usable link syntax, not that underlying authority.

Security Findings and Attack Paths

  • inferred — An author-controlled sibling-file link can now induce a host-file preview after user activation. The same target was already reachable using an absolute link under the same read policy, so this newly accepted syntax does not establish a new privilege escalation or materially increased file-read exposure.

Trust Boundaries and Controls

  • observed — The WebSocket service authenticates the session and installs scope authorization; projects.readFile requires filesystem-read scope. Relative reads retain lexical and realpath containment checks. Absolute host files are presented read-only, and the write operation still requires a workspace-relative target.

Resilience and Maintainability Implications

  • observed — The reused server read operation opens read-only, rejects non-regular files, bounds returned data, and brackets the file handle with release logic. Normalized sibling links inherit these existing failure-containment controls.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: file links that climb out of the workspace now open correctly.
Description check ✅ Passed The description explains the problem, the change, and detailed verification results. It links issue #16354 and includes before-and-after UI evidence. Although it uses different headings from the templ…
Linked Issues check ✅ Passed #16354 requires parent-relative links outside the workspace to resolve as host files and links that remain inside to stay workspace files. resolvePathLinkTarget now collapses path segments before wo…
Out of Scope Changes check ✅ Passed All changes are limited to the web path resolver, its markdown-link integration, and focused tests. These changes support #16354. No unrelated changes appear in the reviewed diff.
Approvability ✅ Passed The diff changes only two web path-resolver files and their tests. It fixes path normalization for existing file links and adds focused coverage. It does not change a product default, suppress a stati…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@macodev00

Copy link
Copy Markdown
Contributor Author

Superseded; redoing from scratch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: A file link with ../ to a file outside the workspace fails to open

1 participant