fix: resolve dangling symlinks during MCP roots path validation#2373
Open
mohammadmseet-hue wants to merge 1 commit into
Open
fix: resolve dangling symlinks during MCP roots path validation#2373mohammadmseet-hue wants to merge 1 commit into
mohammadmseet-hue wants to merge 1 commit into
Conversation
resolveCanonicalPath() walks to the nearest existing ancestor for a not-yet-existing path, but fs.realpath() reports a dangling symlink as ENOENT, so the link name was re-appended verbatim and the returned path stayed inside the root even though the link points outside it. A write to such a link then escapes every configured MCP root. Resolve a component that is itself a symlink via readlink and continue canonicalization from its target, so the path reflects the real write destination and roots validation rejects out-of-root targets. A MAX_SYMLINK_DEPTH guard bounds symlink cycles among not-yet-existing targets. Adds unit tests for a dangling leaf symlink and a dangling intermediate directory symlink.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Harden MCP roots path validation against dangling symlinks in
resolveCanonicalPath()(src/utils/files.ts), used byMcpContext.validatePath()to keep file-writing tools inside the configured workspace roots.Problem
For a not-yet-existing output path,
resolveCanonicalPath()walks up to the nearest existing ancestor, canonicalizes it withfs.realpath(), and re-appends the missing trailing segments.fs.realpath()reports a dangling symlink (a symlink whose target does not exist yet) asENOENT. The walk then treated the link's own name as an ordinary missing segment and appended it verbatim, so the returned canonical path stayed inside the root even though the link points outside it.saveFile()writes to the original unresolved path, the write follows the symlink, and the file lands outside every configured root. This gap remained after the earlier hardening in #2127 and #2269.Fix
In the
ENOENTbranch,lstat()each candidate component. If it is itself a symlink, resolve its target withreadlinkand continue canonicalization from the target. The returned canonical path now reflects the real write destination, sovalidatePath()rejects out-of-root targets. AMAX_SYMLINK_DEPTH = 40guard (mirrorsSYMLOOP_MAX) bounds symlink cycles among not-yet-existing targets.Tests
Adds two unit tests to
tests/utils/files.test.ts:node --test build/tests/utils/files.test.jspasses;prettier --checkandeslintare clean on both files.