# Desktop Commander Security Measures to Prevent Symlink Attacks

> Desktop Commander prevents symlink attacks by resolving symbolic links before validation. Learn how it secures paths and protects your directories.

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

---

**Desktop Commander prevents symlink attacks by resolving all symbolic links in requested paths before validation, ensuring the canonical path lies within allowed directories.**

Desktop Commander is a Model Context Protocol (MCP) client that provides sandboxed file-system access for AI agents. To prevent symlink attacks that could redirect file operations to sensitive system locations like `/etc/passwd`, the codebase implements a rigorous path validation mechanism centered in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts). This defense ensures that even if an attacker places malicious symbolic links inside permitted folders, the resolved canonical path must still fall within a configurable whitelist of safe directories.

## Understanding the Symlink Attack Vector

A **symlink traversal attack** occurs when an attacker creates a symbolic link inside an allowed directory that points to a restricted location outside the sandbox. If the application blindly follows the symlink, it might read or write files in `/etc`, `/root`, or other sensitive areas. The danger is particularly acute when creating new files, as the target path does not yet exist and standard file existence checks fail to reveal parent-directory symlinks.

## Core Defense: The validatePath Function

The heart of the protection is the **`validatePath`** function in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) (lines 44-106). According to the DesktopCommanderMCP source code, this function performs three decisive steps before any file operation executes:

1. **Resolve every symlink** in the requested path, even when the final file does not yet exist.
2. **Normalize the absolute path** and compare it against a whitelist of allowed directories.
3. **Reject the operation** if the resolved path falls outside the whitelist, emitting telemetry for security monitoring.

### Canonicalization with normalizePath and expandHome

Before validation begins, the system normalizes user input through helper functions. The **`normalizePath`** function (lines 34-36) expands the tilde (`~`) and resolves relative components like `.` and `..`, while **`expandHome`** (lines 38-42) ensures cross-platform home directory resolution. This eliminates ambiguity from user input before security checks apply.

### Symlink Resolution for Existing Files

When the target file exists, **`fs.realpath`** (lines 44-48) automatically follows all symbolic links in the path and returns the true canonical location. This handles the straightforward case where the symlink is the final path component.

### The Security Fix for Non-Existent Paths

The critical innovation for preventing symlink attacks occurs when creating new files. Since `fs.realpath` throws `ENOENT` for non-existent paths, the code implements a **"SECURITY FIX"** (comment at line 58) between lines 58-86:

```typescript
// SECURITY FIX: Handle case where file doesn't exist yet
// Resolve symlinks in the parent directory path
let currentDir = absoluteOriginal;
// Walk up until we find an existing directory
while (!fs.existsSync(currentDir)) {
    currentDir = path.dirname(currentDir);
}
// Resolve the existing parent to its real path
const resolvedExisting = fs.realpathSync(currentDir);
// Reconstruct the full path

```

This logic resolves the nearest existing ancestor directory, then re-attaches the non-existent leaf components. By walking up the tree and resolving symlinks at each existing level, the code guarantees that a malicious symlink like `~/projects/malicious -> /etc` cannot redirect a write operation to `/etc/passwd`.

### Whitelist Enforcement with isPathAllowed

The **`isPathAllowed`** function (lines 71-115) performs the final authorization check. It normalizes both the resolved path and each directory in `allowedDirectories`, then verifies:

- **Exact equality** with an allowed directory
- **Sub-directory prefix matching** (ensuring `/home/user` does not match `/home/username`)
- **Windows drive letter** handling for cross-platform compatibility

If the resolved path fails these checks, the function throws an error and logs a `server_path_validation_error` telemetry event via the capture utility in [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts).

## Step-by-Step Path Validation Process

According to the [`filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/filesystem.ts) implementation, every file operation follows this rigorous sequence:

1. **Input processing** — Public APIs like `readFile` or `writeFile` call `validatePath(requestedPath)`.
2. **Path expansion** — `expandHome` and normalization produce an absolute path (`absoluteOriginal`).
3. **Symlink resolution** — If the file exists, `fs.realpath` returns the canonical path. If not, the parent-directory resolution logic walks up the tree, resolving symlinks at each existing level.
4. **Whitelist comparison** — `isPathAllowed` checks if the fully resolved path lies within `allowedDirectories` (configured in [`src/config-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config-manager.ts) at lines 11-25).
5. **Rejection or approval** — Unauthorized paths trigger an immediate exception with telemetry logging.
6. **Canonical path return** — Validated paths are returned to the calling function, ensuring all downstream `fs.readFile`, `fs.writeFile`, or `fs.mkdir` operations use the safe, resolved location.

Because resolution happens **before** any file system call, attackers cannot exploit race conditions (time-of-check to time-of-use) to rewrite symlinks after validation.

## Practical Implementation Examples

The following patterns from [`src/handlers/filesystem-handlers.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/filesystem-handlers.ts) demonstrate secure usage:

### Reading Files with Automatic Validation

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

async function viewDocument(filename: string) {
    // validatePath automatically resolves symlinks and checks whitelist
    const result = await readFile(`~/documents/${filename}`);
    return result.content;
}

```

Even if `~/documents` contains a symlink to `/etc`, the resolved path `/etc/shadow` would fail the whitelist check and throw an error before any read occurs.

### Writing Files Safely

```typescript
import { writeFile } from './tools/filesystem.js';

await writeFile('~/projects/config.txt', 'configuration data', 'rewrite');

```

If a malicious actor created `~/projects -> /etc`, the parent-directory resolution would reveal that the resolved path points outside the allowed directories, preventing the write operation.

### Creating Nested Directories

```typescript
import { createDirectory } from './tools/filesystem.js';

await createDirectory('~/data/2024/reports');

```

The validation walks up through `reports`, `2024`, and `data`, resolving any symlinks at each level before creating the new directory structure.

### Moving Files with Dual Validation

```typescript
import { moveFile } from './tools/filesystem.js';

await moveFile('~/temp/old.txt', '~/archive/old.txt');

```

Both source and destination paths undergo `validatePath` scrutiny, ensuring neither side can exploit symlinks to access restricted areas.

## Configuration and Monitoring

The security model relies on **configuration-driven whitelisting** via [`src/config-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config-manager.ts). The `getAllowedDirs` function (lines 11-25) retrieves `allowedDirectories` from user configuration, defaulting to the home directory if unspecified.

Failed validation attempts trigger telemetry events through the [`capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/capture.ts) utility, allowing administrators to monitor for probing attacks or configuration errors without exposing system details to the error messages.

## Summary

- **`validatePath`** in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) serves as the mandatory security gateway for all file operations.
- **Parent-directory resolution** (the "SECURITY FIX" at lines 58-86) prevents symlink attacks on non-existent file paths by resolving symlinks at every existing directory level.
- **Canonical path whitelisting** via `isPathAllowed` (lines 71-115) enforces strict boundaries with sub-directory prefix matching.
- **Race-condition resistance** is achieved by resolving paths immediately before file operations, eliminating TOCTOU vulnerabilities.
- **Telemetry logging** via `server_path_validation_error` provides security monitoring without information leakage.

## Frequently Asked Questions

### How does Desktop Commander handle broken symlinks?

Desktop Commander treats broken symlinks as security violations. During the resolution phase in `validatePath`, if `fs.realpath` encounters a symlink pointing to a non-existent target, it throws an error that propagates to the user. This conservative approach prevents attackers from using dangling symlinks to probe file system structure or manipulate error handling logic.

### Can attackers exploit race conditions by changing symlinks after validation?

No. The architecture eliminates time-of-check to time-of-use (TOCTOU) race conditions because `validatePath` performs symlink resolution immediately before the file operation occurs within the same synchronous validation step. There is no window between whitelist checking and file access where an attacker could swap a legitimate file for a malicious symlink.

### What directories are considered safe by default?

By default, Desktop Commander restricts all file operations to the user's home directory. Administrators can expand the sandbox by configuring the `allowedDirectories` array in the configuration manager ([`src/config-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config-manager.ts)). Each entry in this array is normalized and validated using the same `isPathAllowed` logic to prevent whitelist entries themselves from containing symlinks.

### Does this protection work on Windows?

Yes. The `isPathAllowed` function (lines 71-115) includes specific logic to handle Windows drive letters and case-insensitive path comparisons. The validation normalizes paths using platform-specific separators and resolves Windows junction points and symbolic links through Node.js's `fs.realpath`, ensuring consistent cross-platform protection against directory traversal attacks.