# How Desktop Commander MCP Prevents Symlink Traversal Attacks in File Operations

> Desktop Commander MCP stops symlink traversal attacks by resolving paths, validating directories, and enforcing policies. Learn how it secures file operations.

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

---

**Desktop Commander MCP blocks symlink traversal attacks by resolving every path to its canonical location using `fs.realpath`, validating parent directories for non-existent targets, and enforcing strict allowed-directory policies before any filesystem operation executes.**

Symlink traversal attacks allow malicious actors to read or write files outside intended directories by exploiting symbolic links. In the Desktop Commander MCP repository, the filesystem security layer ensures that AI agents can only access explicitly permitted locations, even when attackers craft malicious symlink chains.

## Real-Path Resolution in validatePath

The core defense resides in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts), specifically within the `validatePath` function. When any file operation receives a path, the function immediately calls `fs.realpath` on the absolute path to resolve every component—including intermediate symlinks—to its canonical target.

According to the Desktop Commander MCP source code at lines 39-47 in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts), this resolution happens before any directory check:

```typescript
// From src/tools/filesystem.ts - validatePath resolves symlinks first
const realPath = await fs.realpath(absolutePath);
// If path exists, realPath contains the canonical location
// If it contains symlinks, they are fully resolved

```

This ensures that if an attacker places a symlink inside an allowed directory that points to `/etc/passwd` or `C:\Windows\System32`, the validation system sees the true destination path rather than the symlink location.

## Parent-Directory Validation for Non-Existent Targets

Creating new files presents a unique security challenge: the target path does not exist yet, so `fs.realpath` cannot resolve the final component. Desktop Commander MCP handles this by implementing a parent-directory fallback mechanism.

As implemented in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) lines 58-86, the function walks up the directory tree until it finds the deepest existing ancestor, resolves that to its real path, then reconstructs the intended path:

```typescript
// Security-critical: Resolve parent when target doesn't exist
let current = path.dirname(absolutePath);
while (!(await exists(current))) {
  current = path.dirname(current);
}
const realParent = await fs.realpath(current);
// Reconstruct the full path from the validated parent

```

This prevents attackers from creating a non-existent sub-path through a symlink that points outside the allowed tree. Without this check, an attacker could create `allowed_dir/symlink_to_etc/new_file` and bypass restrictions.

## Allowed-Directory Enforcement with isPathAllowed

After path resolution, the `isPathAllowed` function (located in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) lines 77-100) performs the authorization check. It compares the resolved canonical path against the configurable `allowedDirectories` list.

The comparison uses normalized, lower-cased paths with trailing-separator guards to prevent partial-name matches:

- **Exact boundary checking**: Ensures `/allowed/path` matches `/allowed/path/file` but not `/allowed/path_backup`
- **Case normalization**: Handles case-insensitive filesystems correctly
- **Separator normalization**: Handles both forward slashes and backslashes on Windows

If the resolved path is not a sub-directory of any configured allowed entry, the system throws a validation error.

## Security Event Logging and Error Handling

When path validation fails, Desktop Commander MCP logs a `server_path_validation_error` event and rejects the operation with a descriptive error message. As shown in lines 92-99 of [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts), this creates an audit trail for security monitoring:

```typescript
// Security violation handling
if (!isAllowed) {
  server.sendLoggingMessage({
    level: 'error',
    data: `Path validation failed: ${normalizedPath}`
  });
  throw new Error(`Path not allowed: ${requestedPath}`);
}

```

This immediate rejection ensures that no filesystem operation proceeds on paths outside the sandboxed area.

## Comprehensive Security Testing

The repository includes a dedicated test suite at [`test/test-symlink-security.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test/test-symlink-security.js) that validates these protections against realistic attack scenarios. Lines 13-30 create both directory and file symlinks pointing outside the allowed tree and assert that `validatePath` correctly blocks them:

```bash

# Run the symlink security test suite

npm run test:test-symlink-security

# or directly with Node:

node test/test-symlink-security.js

```

These tests simulate attacks where:
- A symlink inside the allowed directory points to `/etc`
- A nested symlink chain attempts to escape the sandbox
- Non-existent paths are created through malicious symlinks

All scenarios verify that the canonical path resolution correctly identifies the true target location and rejects unauthorized access.

## Implementation Example: Configuring Allowed Directories

To leverage these security features, configure the `allowedDirectories` setting before performing file operations:

```typescript
import { configManager } from './config-manager.js';
import { validatePath } from './tools/filesystem.js';

// Restrict operations to a specific sandbox
await configManager.setValue('allowedDirectories', ['/home/user/safe_projects']);

// This succeeds - real path stays within allowed directory
const safeFile = await validatePath('safe_projects/readme.md');

// This fails - resolves to /etc/passwd via symlink
try {
  await validatePath('safe_projects/link_to_passwd');
} catch (e) {
  console.error(e.message); // "Path not allowed: ..."
}

```

## Summary

- **Canonical resolution**: `fs.realpath` in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) resolves all symlinks before directory checks occur.
- **Parent validation**: For non-existent targets, the system validates the deepest existing ancestor to prevent creation through malicious symlinks.
- **Strict boundary enforcement**: `isPathAllowed` uses normalized path comparison with trailing-separator guards to prevent partial directory name matches.
- **Audit logging**: Failed validations trigger `server_path_validation_error` events for security monitoring.
- **Automated verification**: The [`test-symlink-security.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/test-symlink-security.js) suite continuously validates protections against directory traversal attacks.

## Frequently Asked Questions

### How does Desktop Commander MCP detect symlink attacks?

Desktop Commander MCP detects symlink attacks by calling `fs.realpath` in the `validatePath` function before any filesystem operation. This resolves the supplied path to its canonical location, following all symbolic links in the chain. If the resolved path falls outside the configured `allowedDirectories`, the system blocks the operation and logs a validation error.

### What happens when creating a file through a symlink?

When creating a new file where the target does not yet exist, the system uses a parent-directory fallback. It walks up the directory tree to find the deepest existing ancestor, resolves that to its real path using `fs.realpath`, then reconstructs the intended path. If any component resolves outside the allowed directories, the operation fails immediately, preventing attackers from writing to sensitive locations through symlink chains.

### Can an attacker bypass allowed-directory checks using case sensitivity tricks?

No. The `isPathAllowed` function in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) normalizes paths to lowercase before comparison and handles trailing separators explicitly. This prevents bypasses through case variations (e.g., `Allowed_DIR` vs `allowed_dir`) or partial directory name matches (e.g., `/allowed` matching `/allowed_backup`).

### Where is the symlink traversal security documented?

The security design is documented in [`SECURITY.md`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/SECURITY.md) lines 23-27, which identifies directory-restriction bypass via symlinks as a known risk and describes the mitigation strategy. Implementation details appear in the [`README.md`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/README.md) security section, providing user-facing guidance on configuring `allowedDirectories` and understanding the validation workflow.