# How Symlink Traversal Prevention Works in Desktop Commander MCP Path Validation

> Learn how Desktop Commander MCP prevents symlink traversal by resolving symbolic links using fs.realpath before validating paths against allowed directories.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: internals
- Published: 2026-07-14

---

**Desktop Commander MCP prevents symlink traversal attacks by resolving all symbolic links to their canonical targets using `fs.realpath` before validating paths against allowed directories.**

The `validatePath` function in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) serves as the security gatekeeper for the wonderwhy-er/DesktopCommanderMCP repository. Every file system operation routes through this function, ensuring that symbolic links cannot bypass directory restrictions by revealing their true destinations prior to security evaluation.

## The Core Mechanism: Real-Path Resolution

At the heart of the protection lies the `fs.realpath` (or `fs.promises.realpath`) call within `validatePath`. This Node.js API collapses every symbolic link in a path chain to reveal the actual filesystem location. Without this resolution step, a path such as `/allowed/evil → /etc/passwd` would appear to reside within the allowed directory while actually pointing to a restricted system file.

The function maintains a repository-wide `allowedDirectories` list and verifies that the resolved canonical path starts with one of these permitted locations. As implemented in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts), this check occurs only after full symlink resolution, ensuring that security policy evaluates the true target rather than the potentially deceptive link.

## Step-by-Step Validation Process

### Step 1: Canonical Path Resolution

When `validatePath` receives a user-supplied path, it immediately calls `fs.realpath` to obtain the absolute, canonical form. This step traverses any symbolic links in the chain, converting relative segments and link destinations into a concrete filesystem location.

### Step 2: Allowed Directory Verification

After resolution, the function iterates over the `allowedDirectories` array. It checks whether the resolved path starts with any of the permitted directory paths using a strict prefix match. If the resolved location lies outside all allowed directories, the function throws an error and aborts the operation.

### Step 3: Broken Symlink Handling

If a symlink in the chain points to a non-existent target, `fs.realpath` throws an error. The catch block in `validatePath` re-throws this as a clear "Failed to resolve symlink" error. This fail-fast behavior prevents attackers from using dangling symlinks to circumvent security checks or trigger undefined behavior.

## Security Implementation Details

The source code contains explicit security comments documenting the threat model. According to lines 260-262 in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts): *"Without this, an attacker could create a symlink inside an allowed directory that symlink—bypassing the directory restriction check."*

Additionally, lines 301-303 state: *"SECURITY: Always return the resolved path (with symlinks resolved) so that the canonical target, not a symlink that could point outside allowed directories, is used."*

These comments emphasize that the function must return the resolved path—not the original input—to ensure that subsequent operations use the verified canonical location rather than a potentially malicious link.

## Practical Code Examples

The following example demonstrates safe file reading with automatic symlink traversal prevention:

```typescript
import { validatePath, readFile } from './tools/filesystem.js';

async function safeRead(userPath: string) {
  // 1️⃣ Resolve and validate the path
  const safePath = await validatePath(userPath);

  // 2️⃣ Perform the read operation on the verified location
  return await readFile(safePath);
}

// Attempting a symlink attack – will be rejected
await safeRead('/allowed/evil'); // ❌ throws "Access outside allowed directories"

```

This test case from the security suite demonstrates how symlink bypass attempts are blocked:

```typescript
import { validatePath } from '../dist/tools/filesystem.js';
import * as fs from 'fs/promises';
import * as path from 'path';

const ALLOWED_DIR = path.join(__dirname, 'test_symlink_allowed');
const RESTRICTED_DIR = path.join(__dirname, 'test_symlink_restricted');
const SYMLINK_TO_RESTRICTED = path.join(ALLOWED_DIR, 'evil');

// Create a symlink that points outside the allowed area
await fs.symlink(RESTRICTED_DIR, SYMLINK_TO_RESTRICTED);

// This call fails because `validatePath` resolves the symlink to RESTRICTED_DIR
await validatePath(SYMLINK_TO_RESTRICTED); // ❌ throws

```

## Testing Symlink Security

The repository includes a dedicated test suite in [`test/test-symlink-security.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test/test-symlink-security.js) that validates the effectiveness of these protections. This file attempts various symlink-based directory traversal attacks to ensure that `validatePath` correctly rejects paths that resolve outside the allowed boundaries.

## Limitations and Documentation

While the real-path resolution provides robust protection, the project documentation acknowledges remaining security considerations. The [`README.md`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/README.md) file contains a "Known Security Limitations" section, and [`FAQ.md`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/FAQ.md) specifically addresses directory restriction bypasses via symlinks. These documents provide additional context on the security model and potential edge cases that administrators should monitor.

## Summary

- **Canonical resolution first**: `validatePath` uses `fs.realpath` to resolve all symlinks before security checks.
- **Strict directory validation**: The function verifies the resolved path starts with an allowed directory from the `allowedDirectories` list.
- **Fail-fast on broken links**: Dangling symlinks throw explicit errors rather than bypassing security.
- **Source-level documentation**: Security comments at lines 260-262 and 301-303 in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) explain the attack vectors being mitigated.
- **Comprehensive testing**: The [`test/test-symlink-security.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test/test-symlink-security.js) suite validates protection against symlink traversal attacks.

## Frequently Asked Questions

### Can symlink traversal bypass directory restrictions in Desktop Commander MCP?

No. The `validatePath` function in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) resolves all symbolic links using `fs.realpath` before checking against the `allowedDirectories` list. This ensures that even if a user creates a symlink inside an allowed directory pointing to a restricted location, the resolved canonical path is evaluated for security, not the symlink itself.

### What happens if a symlink points to a non-existent file?

The function throws an error. When `fs.realpath` encounters a broken symlink, it raises an exception that `validatePath` catches and re-throws as a "Failed to resolve symlink" error. This prevents attackers from using dangling symlinks to circumvent security checks or exploit race conditions.

### How does validatePath handle nested symbolic links?

`fs.realpath` recursively resolves the entire symlink chain, regardless of nesting depth. Whether the path contains a single symlink or multiple chained links, the API returns the ultimate canonical target. `validatePath` then validates this final destination against the allowed directories, ensuring that multi-hop symlink attacks are also blocked.

### Where can I find the test suite for symlink security?

The dedicated security tests reside in [`test/test-symlink-security.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test/test-symlink-security.js). This file demonstrates various symlink traversal attempts and verifies that the `validatePath` function correctly rejects paths resolving outside permitted directories. The repository also documents known limitations in [`README.md`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/README.md) and attack vectors in [`FAQ.md`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/FAQ.md).