Desktop Commander MCP allowedDirectories Security Model: Why Terminal Commands Bypass Directory Restrictions

Desktop Commander MCP enforces the allowedDirectories restriction only on file-system API operations, while terminal commands execute directly through the OS shell and are only filtered by the optional blockedCommands list, allowing unrestricted access to any path the host user can reach.

The Desktop Commander MCP server implements a dual-layer security architecture that strictly separates file-system access controls from command execution privileges. While the allowedDirectories configuration creates a sandbox for file operations in src/tools/filesystem.ts, it does not constrain terminal commands, which inherit the full permissions of the host environment. Understanding this architectural distinction is critical for administrators deploying the tool in production environments.

How allowedDirectories Enforces File-System Sandboxing

The allowedDirectories security model applies exclusively to file-system operations through a validation layer implemented in src/tools/filesystem.ts. Every public file operation—readFile, writeFile, listDirectory, moveFile, and createDirectory—first invokes the validatePath function before executing.

The validation process performs three critical steps: expanding tilde (~) characters to the home directory, resolving symlinks and parent directory references (..), and checking the resolved absolute path against the list returned by getAllowedDirs. If the configured list is empty or contains the root directory (/ on Unix systems or c: on Windows), the check is bypassed entirely and the operation is permitted.

// src/tools/filesystem.ts – validatePath implementation
const allowedDirectories = await getAllowedDirs();   // ← reads config.allowedDirectories
if (allowedDirectories.includes('/') || allowedDirectories.length === 0) {
    return true;   // empty or root → unrestricted
}
// Path is accepted only if it is exactly an allowed directory or a sub‑directory of one.

This design ensures that file-system APIs cannot escape the configured directories, creating a true sandbox for automated file manipulation.

Why Terminal Commands Ignore allowedDirectories

Terminal command execution follows a completely separate security path defined in src/command-manager.ts, which does not reference allowedDirectories at all. When a command string arrives through the terminal skill, the system extracts executable names using extractCommands and validates them against the blockedCommands array via validateCommand.

The blockedCommands list is optional and empty by default, meaning no commands are blocked unless explicitly configured. Crucially, this validation checks only command names against the blacklist; it performs no path resolution or directory validation.

// src/command-manager.ts – validateCommand implementation
const config = await configManager.getConfig();
const blockedCommands = config.blockedCommands || [];

const allCommands = this.extractCommands(command);
for (const cmd of allCommands) {
    if (blockedCommands.includes(cmd)) {
        return false;           // command is blocked
    }
}
return true;                    // otherwise allowed – no path check

The terminal skill forwards the raw command string directly to the OS shell after this optional command check. Because the shell executes with the host user's privileges, commands like cat /etc/passwd or ls /private/var succeed even when those paths fall outside the allowedDirectories list.

Key Differences Between Security Layers

Security Feature Enforcement Scope Configuration Field Primary Validation File
File-System Access Restricts read/write operations to specific directories allowedDirectories src/tools/filesystem.ts (validatePath)
Command Execution Blocks specific command names only blockedCommands src/command-manager.ts (validateCommand)

File-System Sandbox Characteristics

  • Path resolution: Resolves symlinks and relative paths before validation
  • Root bypass: Empty array or root path disables restrictions
  • Scope: Applies only to MCP file-system tool calls

Command Execution Characteristics

  • Name-based filtering: Checks only the executable name, not arguments or paths
  • Shell inheritance: Commands run in the host environment with full user permissions
  • No path validation: allowedDirectories is never checked during command execution

Configuration Files and Validation Logic

The security model relies on configuration definitions in src/config-field-definitions.ts, which declares both allowedDirectories and blockedCommands with their respective descriptions. The src/config-manager.ts file maintains these values in memory, defaulting allowedDirectories to an empty array (unrestricted) and blockedCommands to an empty array (no blocks).

// Conceptual flow showing the security bypass
async function runTerminalCommand(cmd: string) {
    if (!await commandManager.validateCommand(cmd)) {
        throw new Error('Blocked command');
    }
    // No path validation – the OS shell receives the raw string.
    return execShell(cmd);
}

This architecture mirrors the design philosophy of many "assistant-in-the-loop" developer tools: file-system operations receive sandboxing to prevent accidental data corruption, while terminal access remains unrestricted to preserve the full power of the command line.

Summary

  • File-system sandbox: The allowedDirectories configuration restricts only file-system API calls (readFile, writeFile, etc.) through path validation in src/tools/filesystem.ts.
  • Terminal bypass: Terminal commands execute through the OS shell without path validation, bypassing the allowedDirectories restrictions entirely.
  • Separate command controls: The only restriction on terminal commands is the optional blockedCommands array, which filters by command name rather than directory access.
  • Default permissiveness: Both configurations default to empty arrays, meaning fresh installations have unrestricted file-system and command execution access unless explicitly configured otherwise.

Frequently Asked Questions

Does allowedDirectories prevent terminal commands from accessing sensitive directories?

No. The allowedDirectories restriction applies exclusively to file-system API operations in src/tools/filesystem.ts. Terminal commands execute through the OS shell after only checking the blockedCommands list in src/command-manager.ts, inheriting the host user's full filesystem permissions regardless of the allowed directories configuration.

What happens if I set allowedDirectories to an empty array?

When allowedDirectories is empty or contains the root directory (/ or c:), the validatePath function in src/tools/filesystem.ts bypasses all path checks and permits file operations anywhere on the system. This is the default configuration behavior.

How do I restrict which commands can run in Desktop Commander MCP?

Use the blockedCommands configuration array defined in src/config-field-definitions.ts. The commandManager.validateCommand method extracts command names from the input string and rejects any that match entries in this list. However, this only blocks specific command names; it does not restrict which directories those commands can access.

Why doesn't the security model restrict terminal commands to allowedDirectories?

The architecture treats file-system APIs and shell execution as fundamentally separate concerns. Enforcing directory restrictions on arbitrary shell commands would require complex sandboxing (such as chroot jails or containerization) beyond the scope of the current whitelist approach. The blockedCommands mechanism provides a lightweight alternative for preventing specific dangerous operations without limiting the flexibility of the terminal environment.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →