Skip to content

validateBrowserUrl: file:// URLs are not symlink-hardened (mirrors #356 review P1 #3) #358

Description

@germanescobar

Summary

server/lib/browser-policy.ts:validateBrowserUrl and the matching path check inside electron/main.ts:validatePreviewUrl decide whether a file:// preview URL is allowed with a lexical path.relative(projectRoot, filePath) comparison. A symlink that lives inside the worktree but points to a target outside it passes the check (the link itself is in-worktree), while Chromium follows the symlink and renders the target — the same privilege gap the #357 review surfaced for the new setFiles action.

The fix in #356 (PR #357) was to run both sides of the comparison through realpath before checking. The file:// path through validateBrowserUrl / validatePreviewUrl is on the same boundary and should be hardened identically:

  • server/lib/browser-policy.ts:isPathInside is shared with validateBrowserUrl and would be a natural place to switch to a canonicalized comparison (with a canonicalizeForBoundary helper, mirroring what Browser bridge: drive native file picker so agents can upload without manual intervention #356 added for validateBrowserFilePath).
  • electron/main.ts:isPathInside (around line 121) duplicates the helper for the main-process re-check and needs the same treatment.
  • Tests in server/lib/__tests__/browser-policy.test.ts should cover the new symlink-escape case for file:// URLs the same way the new validateBrowserFilePath tests do.

Why it matters

A v1 Preview pane or an agent-driven controller browser open ./build/index.html resolves to file://…/build/index.html. If the project contains a symlink at build/index.html → /etc/passwd (or any host-readable path), the agent can navigate to a file outside the worktree via the OS file picker or a relative URL, and Chromium will follow the link.

This is the file-preview counterpart to the upload-side gap #356 closed, and the same P1 severity. Worth fixing as a small follow-up so the two surfaces stay consistent.

Acceptance criteria

  • validateBrowserUrl rejects file:// URLs whose realpath target is outside the canonicalized worktree root.
  • electron/main.ts:validatePreviewUrl re-check enforces the same rule.
  • A symlink inside the worktree pointing outside is classified as outside-project / blocked, regardless of the lexical path.
  • Tests cover the symlink-escape case for both the URL policy and the main-process re-check.
  • No regression to the existing project-relative / absolute / localhost path tests.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions