modelcontextprotocol/servers · error · Error

Access denied - Windows-style path received on a POSIX host:

Error message

Access denied - Windows-style path received on a POSIX host: ${requestedPath}

What it means

On POSIX hosts validatePath rejects Windows-style absolute paths (drive letter followed by \ or /, or a bare drive like 'C:'). Accepting them would silently create a literal file named 'C:\\Users\\...' inside the allowed root while reporting success for the wrong location. The error is thrown before any filesystem access.

Source

Thrown at src/filesystem/lib.ts:146

      return path.join(currentPath, ...relativeParts.slice(index));
    }

    currentPath = await fs.realpath(path.join(currentPath, equivalentMatches[0]));
    if (!isPathWithinAllowedDirectories(normalizePath(currentPath), allowedDirectories)) {
      throw new Error(`Access denied - symlink target outside allowed directories: ${currentPath} not in ${allowedDirectories.join(', ')}`);
    }
  }

  return currentPath;
}

export async function validatePath(requestedPath: string): Promise<string> {
  const expandedPath = expandHome(requestedPath);
  // Do not silently reinterpret a Windows drive path as a relative POSIX path.
  // This would create a literal filename such as `C:\\Users\\...` inside the
  // allowed root and report success for the wrong location.
  if (process.platform !== 'win32' && /^(?:[A-Za-z]:)(?:[\\/]|$)/.test(expandedPath)) {
    throw new Error(`Access denied - Windows-style path received on a POSIX host: ${requestedPath}`);
  }
  const absolute = path.isAbsolute(expandedPath)
    ? path.resolve(expandedPath)
    : resolveRelativePathAgainstAllowedDirectories(expandedPath);

  const normalizedRequested = normalizePath(absolute);

  // Security: Check if path is within allowed directories before any file operations
  const isAllowed = isPathWithinAllowedDirectories(normalizedRequested, allowedDirectories);
  if (!isAllowed) {
    throw new Error(`Access denied - path outside allowed directories: ${absolute} not in ${allowedDirectories.join(', ')}`);
  }

  // Security: Handle symlinks by checking their real path to prevent symlink attacks
  // This prevents attackers from creating symlinks that point outside allowed directories
  try {
    const realPath = await fs.realpath(absolute);
    const normalizedReal = normalizePath(realPath);

View on GitHub (pinned to 579c3903f3)

Solutions

  1. Convert the path to its POSIX form (e.g. '/mnt/c/Users/me/file.txt' under WSL) before calling the tool
  2. Use a POSIX absolute or home-relative path like '~/file.txt' that exists on the host
  3. Fix the caller/config to detect the platform and emit platform-appropriate paths

Example fix

// before (on Linux)
await read_file('C:\\Users\\me\\notes.txt');
// after
await read_file('/mnt/c/Users/me/notes.txt'); // WSL, or a native POSIX path
Defensive patterns

Strategy: validation

Validate before calling

const WIN_PATH = /^(?:[A-Za-z]:)(?:[\\/]|$)/;
if (process.platform !== 'win32' && WIN_PATH.test(p)) {
  throw new Error(`Refusing Windows-style path on POSIX host: ${p}`);
}

Type guard

function isWindowsStylePath(p: string): boolean {
  return /^(?:[A-Za-z]:)(?:[\\/]|$)/.test(p);
} // guard callers before invoking the tool

Prevention

When it happens

Trigger: Passing a path like 'C:\\Users\\me\\file.txt' or 'C:/Users/me' to any filesystem tool while the server runs on Linux/macOS — typically from a config or script authored on Windows.

Common situations: Sharing MCP client configs or tool arguments between Windows and POSIX machines; WSL sessions receiving Windows paths from the Windows side; hardcoded paths in CI scripts copied from Windows developers.

Understand the failure class

Related errors


AI-assisted analysis of modelcontextprotocol/servers@579c3903f3 (2026-09-01). Data as JSON: /api/errors/dd6bc7531e5da2dc. Report an issue: GitHub.