{"record":{"id":"93576910c6daeafe","repo":"JuliusBrussee/caveman","slug":"cannot-safely-launch-non-node-windows-command-shim-935769","errorCode":null,"errorMessage":"cannot safely launch non-Node Windows command shim: ${executable}","messagePattern":"cannot safely launch non-Node Windows command shim: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/mcp-servers/caveman-shrink/spawn-options.js","lineNumber":52,"sourceCode":"      const candidate = path.join(directory, name);\n      if (fs.existsSync(candidate)) return candidate;\n    }\n  }\n  return null;\n}\n\nfunction getSpawnInvocation(command, args, platform = process.platform, env = process.env) {\n  if (platform !== 'win32') return { command, args: [...args] };\n  const executable = resolveWindowsCommand(command, env) || command;\n  if (!/\\.(?:cmd|bat)$/i.test(executable)) return { command: executable, args: [...args] };\n  const source = fs.readFileSync(executable, 'utf8');\n  let relativeScript = null;\n  for (const line of source.split(/\\r?\\n/)) {\n    if (!/(?:\\bnode(?:\\.exe)?\\b|_prog)/i.test(line) || !/%\\*/.test(line)) continue;\n    const match = line.match(/\"%(?:dp0%|~dp0)\\\\([^\"\\r\\n]+\\.(?:cjs|mjs|js))\"\\s+%\\*/i);\n    if (match) { relativeScript = match[1]; break; }\n  }\n  if (!relativeScript) throw new Error(`cannot safely launch non-Node Windows command shim: ${executable}`);\n  const script = path.resolve(path.dirname(executable), ...relativeScript.split(/[\\\\/]+/));\n  if (!fs.statSync(script).isFile()) throw new Error(`Windows command shim target is missing: ${script}`);\n  return { command: process.execPath, args: [script, ...args] };\n}\n\nfunction getSpawnOptions(platform = process.platform) {\n  return {\n    stdio: ['pipe', 'pipe', 'inherit'],\n    windowsHide: true,\n  };\n}\n\nmodule.exports = { getSpawnInvocation, getSpawnOptions, resolveWindowsCommand };\n","sourceCodeStart":34,"sourceCodeEnd":66,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/src/mcp-servers/caveman-shrink/spawn-options.js#L34-L66","documentation":"getSpawnInvocation() in the caveman-shrink MCP server refuses to run a .cmd/.bat shim on Windows unless it can prove the shim launches a Node script. It scans the shim source for the npm-generated pattern (node/_prog plus %* forwarding to a %~dp0 script target) and, finding none, throws rather than spawn the .bat directly — the direct spawn would be the CVE-2024-27980 command-injection vector Node itself blocks.","triggerScenarios":"Configuring the MCP server command as npx/npm .cmd shims on win32 whose content does not match the standard npm shim template — a custom wrapper .bat, a shim generated by a non-npm package manager (pnpm/yarn custom wrappers), or an edited shim.","commonSituations":"Package managers generating differently-shaped shims; hand-written .bat wrappers around node scripts; older or newer npm emitting a template the regexes do not recognize.","solutions":["Point the MCP server config directly at node with the JS entrypoint as the first argument instead of the .cmd shim","Reinstall the package with the npm version the shim template comes from so the pattern matches","If you control the shim, regenerate it via npm (npm install/rebuild) so it uses the standard node/%~dp0 forwarding"],"exampleFix":"// before (mcp config)\n{ \"command\": \"npx\", \"args\": [\"caveman-shrink\"] } // resolves to a .cmd shim on Windows\n\n// after\n{ \"command\": \"node\", \"args\": [\"C:\\\\path\\\\to\\\\node_modules\\\\caveman-shrink\\\\bin\\\\cli.mjs\"] }","handlingStrategy":"fallback","validationCode":"const isWin = process.platform === \"win32\";\nconst command = isWin ? process.execPath : \"npx\";\nconst args = isWin ? [resolveToRealJsEntry()] : [\"caveman-shrink\"];","typeGuard":null,"tryCatchPattern":"try {\n  spawn(cmd, args);\n} catch (e) {\n  if (/cannot safely launch non-Node Windows command shim/.test(String(e?.message))) {\n    spawn(process.execPath, [realJsEntryPoint, ...args]); // fallback: direct node invocation\n  } else throw e;\n}","preventionTips":["On Windows, configure MCP servers with command \"node\" plus the package's JS entrypoint instead of npx or .cmd shims","Reinstall packages with current npm so shims use the standard template","Pin package manager and npm versions consistently across the team"],"tags":["windows","spawn","security","mcp"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}