Skip to content

filesystem: decide whether to refuse NTFS alternate-data-stream paths (file:stream) on Windows #5375

Closed

Description

@cliffhall

Problem

On Windows, NTFS lets a path name an alternate data stream with a colon after the file name (file.txt:stream). The filesystem server's path validation (isPathWithinAllowedDirectories in path-validation.ts) accepts such a path whenever the file part lies inside an allowed directory, so the tools can read and write alternate streams there, and a stream written that way is invisible to ordinary directory listings and to most tools a user would check with.

A first look suggests the containment holds: a stream on a file inside an allowed directory is stored in that file, and a stream suffix on the allowed directory itself (C:\allowed:stream) fails the containment check. So the open question is whether the server should refuse alternate-stream paths anyway, as defense in depth and to keep hidden data out of reach of the tools, or keep accepting them.

Expected behavior

A decision, either way. If the server should refuse them: on Windows, reject a path holding a colon anywhere but the drive-letter prefix, with a clear error, cover it with tests, and note it in the filesystem README.

Reference prototype

#4523 by @andreiminca rejects paths with a colon beyond the drive-letter prefix on Windows, in isPathWithinAllowedDirectories. It was opened before this repository moved to issues-only contributions, and is closed in favor of this issue; it serves as the reference prototype for the fix, and its author will be credited when the fix ships.

Activity

  1. added
    enhancementNew feature or request
    server-filesystemReference implementation for the Filesystem MCP server - src/filesystem
    on Oct 28, 2026
  2. cliffhall commented on Oct 28, 2026

    @cliffhall
    MemberAuthor

    Triage: Priority Low (total 4)

    • Severity 2: alternate streams stay inside the allowed directories as far as a first look shows; the concern is hidden data within them, and the change is defense in depth
    • Urgency 2: wanted eventually, nothing blocked on it
    • Bonuses: none

    Board: Servers V2 (#43), Status Incoming, awaiting maintainer review (no milestone yet).

  3. youlemei2022-web commented on Oct 29, 2026

    @youlemei2022-web

    My vote: refuse them, and treat "containment holds" as the wrong test.

    The containment argument answers "does the write land inside the allowed directory?" but the security property a filesystem server actually provides is closer to "the user can see and review what changed". An alternate stream breaks exactly that: it does not appear in dir, it does not show up in a diff, many sync and backup tools ignore it, and a reviewer looking at the file afterwards sees an unchanged file with extra bytes attached.

    Two more specifics worth putting in the issue before the decision:

    1. This is a storage channel, not just a hidden byte range. file.txt:hidden can hold arbitrary size without changing the visible file, so a caller that can write ADS can hide payloads inside an allowed directory while every listing and hash of the visible file stays identical.
    2. The legitimate uses are narrow and read-mostly. :Zone.Identifier is the common one (mark-of-the-web). Everything else - :evil, :$DATA variants, :stream:$DATA - is either pointless or actively evasive. That argues for "reject writes to any stream, allow listing/reading :Zone.Identifier if you need it", rather than blanket acceptance.

    If you go with rejection, the check should be slightly wider than "colon beyond the drive prefix", because the same class of bypass has a few neighbours on Windows:

    • C:\dir\file.txt:stream - ADS (the issue at hand)
    • C:\dir\file.txt::$DATA - default stream spelled explicitly
    • \\?\C:\dir\... - long-path prefix that skips normalisation
    • C:\dir\CON, C:\dir\NUL - device names that resolve elsewhere
    • C:\dir\file.txt. / trailing space - stripped by Win32, so two paths name one file

    Tests worth having: drive-relative (C:file.txt), UNC (\\server\share\file.txt:stream), and a stream attached to a directory (C:\allowed:stream, which you already note fails containment - worth pinning so it stays that way).

    Disclosure: I maintain MOOGH, a Windows desktop agent that hands these same filesystem tools to a model, so this is a daily concern rather than a theoretical one. No link - happy to turn the list above into test cases in a PR if that helps you decide.

  4. added this to the v2.4.0 milestone on Oct 29, 2026
  5. self-assigned this
    on Nov 5, 2026
  6. cliffhall commented on Nov 5, 2026

    @cliffhall
    MemberAuthor

    Decision: refuse alternate-data-stream paths on Windows. A colon anywhere but the drive-letter prefix is now refused with a clear error by every tool; POSIX is unaffected. Implemented in #5450, following the #4523 prototype. The suggested device-name (CON, NUL) and trailing dot/space checks are out of this issue's scope and are tracked in #5444.

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

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestserver-filesystemReference implementation for the Filesystem MCP server - src/filesystemv2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions