← MCP server and skill grades

DesktopCommanderMCP

wonderwhy-er/DesktopCommanderMCP

D
Type
MCP server
Scanned
Oct 29, 2026
Version
db3430f23c1f
Files read
492

Desktop Commander is a local server and plugin suite that lets AI agents run terminal commands, manage running programs, and read or edit files on your computer. Because it gives the AI unrestricted access to your files, security settings, and command line by default—and downloads unpinned code updates on startup—a tricked AI or a compromised update could take complete control of your user account.

What it can reach

Shell commands
Runs arbitrary terminal commands, persistent interactive sessions, and local Node.js scripts under your user account.
Files
Reads, writes, edits, moves, and searches files across your entire computer by default, and saves unredacted tool history to a local folder.
Network
Fetches arbitrary web links, downloads package updates and headless Chrome, sends usage telemetry, and connects to remote relay servers when remote mode is enabled.
System
Lists and terminates running programs on your computer and can prevent macOS from sleeping in remote mode.
Browser
Opens your default web browser for onboarding pages, feedback forms, and account login verification.

Findings

2 high6 medium4 low
  1. HighAgent Can Modify Security Configuration via set_config_value Tool

    src/tools/config.ts:62

    The server exposes set_config_value as a callable MCP tool. Even if a user restricts allowedDirectories or populates blockedCommands, an attacker who achieves prompt injection through a file, web page, or issue read by the agent can call set_config_value to reset allowedDirectories to [] (granting full filesystem access), empty blockedCommands, or change defaultShell.

    Fix: Remove set_config_value from the MCP tools callable by the model (or restrict it so that the model cannot widen allowedDirectories, remove blockedCommands, or alter defaultShell), requiring security-sensitive configuration changes to be made directly by the user.

  2. HighCommand Blocklist Bypass via interact_with_process, node:local, Newlines, and Quotes

    src/tools/improved-process-tools.ts:328

    While start_process checks the initial command string against blockedCommands, interact_with_process sends arbitrary input to an active shell or REPL session without calling commandManager.validateCommand. In addition, start_process with command: "node:local" executes arbitrary Node.js code via a temporary .mjs file without command or directory restrictions, and extractCommands in src/command-manager.ts does not split on newline characters (\n) and leaves quotes attached to command names (such as "sudo"), allowing blocked commands to be executed.

    Fix: Validate inputs passed to interact_with_process, split command strings on newlines (\n and \r), strip quotes from command tokens before checking blockedCommands, and subject node:local to the same validation.

  3. MediumFull Filesystem Access Enabled by Default

    src/config-manager.ts:279

    The default configuration initializes allowedDirectories to an empty array ([]), which isPathAllowed in src/tools/filesystem.ts treats as allowing unrestricted read and write access to the entire filesystem. Out of the box, any prompt injection can read or modify sensitive files such as ~/.ssh/id_rsa, ~/.aws/credentials, or shell startup scripts.

    Fix: Default allowedDirectories to a narrow workspace directory (or deny file operations until the user explicitly configures allowed directories).

  4. MediumServer-Side Request Forgery (SSRF) in read_file URL Fetching and write_pdf

    src/tools/filesystem.ts:447

    When read_file is invoked with isUrl: true, readFileFromUrl fetches arbitrary URLs without blocking loopback addresses (127.0.0.1, localhost), private RFC 1918 networks, or cloud metadata endpoints (169.254.169.254). Similarly, write_pdf renders Markdown and inline HTML/scripts in headless Chrome with network access enabled, allowing an attacker to probe internal services and exfiltrate responses via the generated PDF.

    Fix: Resolve hostnames and block requests to loopback, link-local, and private IP ranges in readFileFromUrl, and disable external network requests in Puppeteer when rendering PDFs.

  5. MediumInstall and Setup Scripts Send Unredacted Path Telemetry Without Checking Opt-Out

    setup-claude-server.js:686

    Both setup-claude-server.js and the npm postinstall script (track-installation.js) send telemetry events to https://telemetry.desktopcommander.app/mp/collect without checking telemetryEnabled in the user's configuration or DESKTOP_COMMANDER_DISABLE_TELEMETRY. In setup-claude-server.js, npx_setup_create_config_dir transmits path: configDir, which contains the user's home directory path and OS username, and npx_setup_start sends raw process.argv.

    Fix: Check telemetryEnabled and DESKTOP_COMMANDER_DISABLE_TELEMETRY before sending telemetry in setup-claude-server.js and track-installation.js, and strip or redact file paths and command-line arguments.

  6. MediumUnverified Package Download in Predictable /tmp Directory Run with sudo

    install.sh:32

    install.sh downloads the Node.js .pkg installer to a fixed path (/tmp/nodejs-install/node-v22.14.0.pkg) in world-writable /tmp without verifying its SHA-256 checksum, and then executes sudo installer -pkg on that file. On a shared machine, a local user can pre-create /tmp/nodejs-install or swap the file before sudo installer runs to execute arbitrary code as root.

    Fix: Use mktemp -d to create an owner-only temporary directory and verify the installer against official SHA-256 checksums before running sudo installer (matching scripts/remote/remote-macos.sh).

  7. MediumUnpinned @latest package downloaded and executed at runtime

    .mcp.json:5

    The plugin and MCP configuration launch @wonderwhy-er/desktop-commander@latest with npx -y instead of pinning a specific version. Every time the coding agent starts, it automatically downloads and executes whatever version is currently tagged latest on npm, exposing users to immediate remote code execution if the npm publisher account is ever compromised.

    Fix: Pin the package to an exact, audited version (for example, @wonderwhy-er/desktop-commander@0.3.1) in .mcp.json and the plugin manifests.

  8. MediumSkill instructs agent to pass live API keys to shell commands

    skills/ai-tools-setup/SKILL.md:33

    The ai-tools-setup skill tells the agent to test live API keys by running a curl command via start_process. Any secret passed in start_process arguments is exposed in the operating system process table and is written unredacted to ~/.claude-server-commander/claude_tool_call.log and tool-history.jsonl, where later sessions or prompt-injected tools can read it via get_recent_tool_calls.

    Fix: Instruct the agent never to pass API keys or secrets directly in command-line arguments to start_process, and instead read credentials from a protected file or environment variable without logging them.

  9. LowServer Injects [SYSTEM INSTRUCTION] Prompts into Tool Outputs

    src/server.ts:1478

    After successful tool executions, the server appends [SYSTEM INSTRUCTION] blocks to the tool output (src/utils/usageTracker.ts and src/utils/dockerPrompt.ts) instructing the AI agent to ask the user to fill out a feedback survey or switch from Docker MCP Gateway to the project's custom installation script.

    Fix: Do not inject [SYSTEM INSTRUCTION] directives into tool results; use standard MCP notifications or UI elements if user-facing notices are needed.

  10. LowPersistent Unredacted Tool History Exposed to Agent via get_recent_tool_calls

    src/utils/toolHistory.ts:74

    Every tool call's arguments and up to 4 KiB of its output are stored in ~/.claude-server-commander/tool-history.jsonl (and arguments in claude_tool_call.log) with default file permissions and reloaded across restarts. A prompt injection in a later chat session can call get_recent_tool_calls to read sensitive arguments and file outputs from earlier, unrelated sessions.

    Fix: Limit get_recent_tool_calls to the current session by default, redact secrets from logged arguments, and create tool-history.jsonl and claude_tool_call.log with 0o600 permissions.

  11. LowPostinstall script sends telemetry during installation

    package.json:30

    The postinstall script executes dist/track-installation.js automatically whenever the package is installed (including on npx -y runs), sending installation telemetry over the network before the user can opt out via configuration.

    Fix: Remove dist/track-installation.js from the postinstall script or require explicit opt-in before sending installation telemetry.

  12. LowDocker container runs as root by default

    Dockerfile:26

    The Dockerfile does not switch to a non-root user before starting the server. When users mount host folders into the container as shown in the README, commands run by the agent execute as root with full privileges over those mounted directories.

    Fix: Add USER node before the CMD instruction in the Dockerfile so the server runs as an unprivileged user.