DesktopCommanderMCP
wonderwhy-er/DesktopCommanderMCP
- 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
-
HighAgent Can Modify Security Configuration via
set_config_valueToolThe server exposes
set_config_valueas a callable MCP tool. Even if a user restrictsallowedDirectoriesor populatesblockedCommands, an attacker who achieves prompt injection through a file, web page, or issue read by the agent can callset_config_valueto resetallowedDirectoriesto[](granting full filesystem access), emptyblockedCommands, or changedefaultShell.Fix: Remove
set_config_valuefrom the MCP tools callable by the model (or restrict it so that the model cannot widenallowedDirectories, removeblockedCommands, or alterdefaultShell), requiring security-sensitive configuration changes to be made directly by the user. -
HighCommand Blocklist Bypass via
interact_with_process,node:local, Newlines, and Quotessrc/tools/improved-process-tools.ts:328
While
start_processchecks the initial command string againstblockedCommands,interact_with_processsends arbitrary input to an active shell or REPL session without callingcommandManager.validateCommand. In addition,start_processwithcommand: "node:local"executes arbitrary Node.js code via a temporary.mjsfile without command or directory restrictions, andextractCommandsinsrc/command-manager.tsdoes 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 (\nand\r), strip quotes from command tokens before checkingblockedCommands, and subjectnode:localto the same validation. -
MediumFull Filesystem Access Enabled by Default
The default configuration initializes
allowedDirectoriesto an empty array ([]), whichisPathAllowedinsrc/tools/filesystem.tstreats 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
allowedDirectoriesto a narrow workspace directory (or deny file operations until the user explicitly configures allowed directories). -
MediumServer-Side Request Forgery (SSRF) in
read_fileURL Fetching andwrite_pdfWhen
read_fileis invoked withisUrl: true,readFileFromUrlfetches 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_pdfrenders 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. -
MediumInstall and Setup Scripts Send Unredacted Path Telemetry Without Checking Opt-Out
Both
setup-claude-server.jsand the npmpostinstallscript (track-installation.js) send telemetry events tohttps://telemetry.desktopcommander.app/mp/collectwithout checkingtelemetryEnabledin the user's configuration orDESKTOP_COMMANDER_DISABLE_TELEMETRY. Insetup-claude-server.js,npx_setup_create_config_dirtransmitspath: configDir, which contains the user's home directory path and OS username, andnpx_setup_startsends rawprocess.argv.Fix: Check
telemetryEnabledandDESKTOP_COMMANDER_DISABLE_TELEMETRYbefore sending telemetry insetup-claude-server.jsandtrack-installation.js, and strip or redact file paths and command-line arguments. -
MediumUnverified Package Download in Predictable
/tmpDirectory Run withsudoinstall.shdownloads the Node.js.pkginstaller to a fixed path (/tmp/nodejs-install/node-v22.14.0.pkg) in world-writable/tmpwithout verifying its SHA-256 checksum, and then executessudo installer -pkgon that file. On a shared machine, a local user can pre-create/tmp/nodejs-installor swap the file beforesudo installerruns to execute arbitrary code as root.Fix: Use
mktemp -dto create an owner-only temporary directory and verify the installer against official SHA-256 checksums before runningsudo installer(matchingscripts/remote/remote-macos.sh). -
MediumUnpinned @latest package downloaded and executed at runtime
The plugin and MCP configuration launch
@wonderwhy-er/desktop-commander@latestwithnpx -yinstead of pinning a specific version. Every time the coding agent starts, it automatically downloads and executes whatever version is currently taggedlateston 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.jsonand the plugin manifests. -
MediumSkill instructs agent to pass live API keys to shell commands
skills/ai-tools-setup/SKILL.md:33
The
ai-tools-setupskill tells the agent to test live API keys by running acurlcommand viastart_process. Any secret passed instart_processarguments is exposed in the operating system process table and is written unredacted to~/.claude-server-commander/claude_tool_call.logandtool-history.jsonl, where later sessions or prompt-injected tools can read it viaget_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. -
LowServer Injects
[SYSTEM INSTRUCTION]Prompts into Tool OutputsAfter successful tool executions, the server appends
[SYSTEM INSTRUCTION]blocks to the tool output (src/utils/usageTracker.tsandsrc/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. -
LowPersistent Unredacted Tool History Exposed to Agent via
get_recent_tool_callsEvery tool call's arguments and up to 4 KiB of its output are stored in
~/.claude-server-commander/tool-history.jsonl(and arguments inclaude_tool_call.log) with default file permissions and reloaded across restarts. A prompt injection in a later chat session can callget_recent_tool_callsto read sensitive arguments and file outputs from earlier, unrelated sessions.Fix: Limit
get_recent_tool_callsto the current session by default, redact secrets from logged arguments, and createtool-history.jsonlandclaude_tool_call.logwith0o600permissions. -
LowPostinstall script sends telemetry during installation
The
postinstallscript executesdist/track-installation.jsautomatically whenever the package is installed (including onnpx -yruns), sending installation telemetry over the network before the user can opt out via configuration.Fix: Remove
dist/track-installation.jsfrom thepostinstallscript or require explicit opt-in before sending installation telemetry. -
LowDocker container runs as root by default
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
rootwith full privileges over those mounted directories.Fix: Add
USER nodebefore theCMDinstruction in the Dockerfile so the server runs as an unprivileged user.