registry  /  @tokor/desktop-commander  /  0.2.47

@tokor/desktop-commander@0.2.47

MCP server for terminal operations and file editing

AI Security Review

scanned 3h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No unconsented install-time agent control hijack was confirmed. The risky surface is explicit user-invoked Claude MCP setup plus telemetry and broad MCP filesystem/shell tools.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
npm postinstall verifies ripgrep; user runs setup/bin or desktop-commander setup for Claude config mutation
Impact
Warn-level agent extension lifecycle risk, not confirmed malware
Mechanism
explicit MCP server setup and telemetry collection
Rationale
Static inspection does not show credential theft, destructive behavior, remote payload execution, or unconsented postinstall mutation of Claude config. Because explicit setup mutates an AI-agent control surface and package identity is inconsistent with the configured upstream package name, warn rather than block.
Evidence
package.jsondist/npm-scripts/verify-ripgrep.jsdist/setup-claude-server.jsdist/track-installation.jsdist/index.jsdist/utils/capture.jsdist/config-manager.jsdist/uninstall-claude-server.js
Network endpoints2
telemetry.desktopcommander.app/mp/collectdc-telemetry-proxy-83847352264.europe-west1.run.app/mp/collect

Decision evidence

public snapshot
AI called this Suspicious at 82.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • dist/setup-claude-server.js explicit setup command writes Claude Desktop MCP config and restarts Claude.
  • dist/setup-claude-server.js and dist/track-installation.js send install/setup telemetry to telemetry.desktopcommander.app with environment/install context.
  • package.json metadata/bin setup references desktop-commander but setup config installs @wonderwhy-er/desktop-commander, not @tokor/desktop-commander.
Evidence against
  • package.json postinstall only runs dist/npm-scripts/verify-ripgrep.js and ignores failure.
  • dist/npm-scripts/verify-ripgrep.js only resolves ripgrep path and prints warnings; no config writes or network.
  • dist/index.js setup/remove/remote actions are argument-gated; normal import starts MCP server.
  • dist/utils/capture.js supports telemetry opt-out via config and DESKTOP_COMMANDER_DISABLE_TELEMETRY.
  • Shell/file/process capabilities are MCP server features aligned with package description.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShell
Supply chain
HighEntropyStringsMinifiedObfuscatedUrlStrings
ManifestNo manifest risk signals triggered.
scanned 121 file(s), 2.50 MB of source, external domains: calendar.app.google, claude.ai, dc-telemetry-proxy-83847352264.europe-west1.run.app, desktopcommander.app, discord.com, example.com, github.com, json-schema.org, mcp.desktopcommander.app, prosemirror.net, schemas.openxmlformats.org, tally.so, telemetry.desktopcommander.app, www.google.com

Source & flagged code

5 flagged · loading source
package.jsonView file
scripts.postinstall = node dist/npm-scripts/verify-ripgrep.js || node -e "process.exit(0)"
Critical
Red Install Lifecycle Script

Install-time lifecycle script matches a deterministic static-gate block pattern.

package.jsonView on unpkg
scripts.postinstall = node dist/npm-scripts/verify-ripgrep.js || node -e "process.exit(0)"
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
dist/ui/config-editor/config-editor-runtime.jsView file
25path: iss.path ? [${Ge($)}, ...iss.path] : [${Ge($)}] L26: })));`),p.write(`newResult[${Ge($)}] = ${x}.value`)}p.write("payload.value = newResult;"),p.write("return payload;");let I=p.compile();return($,x)=>I(m,$,x)},r,o=at,a=!Tr.jitless,u... L27: `)}var ir=e=>(t,n,i,r)=>{let o=i?Object.assign(i,{async:!1}):{async:!1},a=t._zod.run({value:n,issues:[]},o);if(a instanceof Promise)throw new Re;if(a.issues.length){let s=new(r?.Er...
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/ui/config-editor/config-editor-runtime.jsView on unpkg · L25
dist/tools/fuzzySearch.jsView file
14const WORKER_CODE = ` L15: const { workerData, parentPort } = require('worker_threads'); L16: import(workerData.moduleUrl)
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/tools/fuzzySearch.jsView on unpkg · L14
dist/track-installation.jsView file
14import { randomUUID } from 'crypto'; L15: import * as https from 'https'; L16: import { platform } from 'os'; ... L21: const __filename = fileURLToPath(import.meta.url); L22: const __dirname = path.dirname(__filename); L23: L24: // Debug logging utility - configurable via environment variables L25: const DEBUG_ENABLED = process.env.DEBUG === 'desktop-commander' || L26: process.env.DEBUG === '*' || ... L58: const configData = fs.readFileSync(CONFIG_FILE, 'utf8'); L59: const config = JSON.parse(configData); L60: if (config.clientId) {
High
Sandbox Evasion Gated Capability

Source gates dangerous network, credential, or execution behavior behind CI, host, platform, time, or geo fingerprint checks.

dist/track-installation.jsView on unpkg · L14

Findings

1 Critical2 High4 Medium7 Low
CriticalRed Install Lifecycle Scriptpackage.json
HighInstall Time Lifecycle Scriptspackage.json
HighSandbox Evasion Gated Capabilitydist/track-installation.js
MediumDynamic Requiredist/tools/fuzzySearch.js
MediumNetwork
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowEvaldist/ui/config-editor/config-editor-runtime.js
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings