Skip to content

fix(filesystem): do not follow symlinks when reporting sizes in list_directory_with_sizes - #4732

Open
annatchijova wants to merge 2 commits into
modelcontextprotocol:mainfrom
annatchijova:filesystem/list-sizes-no-follow-symlink
Open

fix(filesystem): do not follow symlinks when reporting sizes in list_directory_with_sizes#4732
annatchijova wants to merge 2 commits into
modelcontextprotocol:mainfrom
annatchijova:filesystem/list-sizes-no-follow-symlink

Conversation

@annatchijova

Copy link
Copy Markdown

Problem

list_directory_with_sizes stats each entry with fs.stat, which follows symlinks. When an allowed directory contains a symlink that points outside the sandbox, the tool reports the target's size and mtime — disclosing metadata about files outside the allowed directories, which the tool's own description says it "only works within." The sibling tools are consistent the other way: list_directory and directory_tree classify entries from the non-following Dirent, and read_file rejects out-of-sandbox targets via the realpath check in validatePath. This tool was the only one that followed symlinks out of the sandbox.

Fix

Use fs.lstat so a symlink is described by its own metadata, matching the other listing tools. One line (plus a comment). Content was never exposed (reads go through validatePath); this closes the metadata leak.

Repro (before the fix)

An allowed dir containing leak_link -> /etc/hostname: list_directory_with_sizes reports leak_link's size as 9 (the size of /etc/hostname). With fs.lstat it reports the link's own size (13) instead. A regression test asserting this is included.

Scope / severity

Low. Metadata only (size/mtime/existence), and it requires a pre-existing symlink in an allowed directory — the server exposes no symlink-creating tool (write uses wx+atomic-rename, move uses rename), so a client cannot fabricate the symlink through the server. Still a genuine confinement-boundary break worth closing, and it aligns this tool with list_directory / directory_tree.

Alternative fix (if a maintainer prefers)

Keep fs.stat for in-sandbox symlinks but re-validate first: await validatePath(entryPath) and skip entries that resolve outside the allowed set (the pattern searchFilesWithValidation uses). lstat was chosen as the minimal change consistent with list_directory / directory_tree.

annatchijova and others added 2 commits September 1, 2026 11:37
…directory_with_sizes

list_directory_with_sizes stat'd each entry with fs.stat, which follows symlinks.
When an allowed directory contains a symlink that points outside the sandbox, the
tool reported the size and mtime of the symlink target -- disclosing metadata about
files outside the allowed directories, which the tool's own description says it must
not touch. The sibling tools (list_directory, directory_tree) classify entries from
the non-following Dirent, and read_file rejects out-of-sandbox targets via the
realpath check in validatePath; only this tool followed symlinks.

Use fs.lstat so a symlink is described by its own metadata, matching the other
listing tools. Content was never exposed (reads go through validatePath); this closes
the metadata leak.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWmkpCnuhCPKFPD2fexY1a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant