直接用child_process.exec调用shell命令极危险,因它将字符串原样交shell解析,用户输入含分号、$()等特殊字符时会触发命令注入;应改用spawn传参数数组,天然隔离shell解析层。

为什么直接用 child_process.exec 调用 shell 命令很危险
它会把字符串原样喂给 shell 解析,一旦参数含空格、$()、反引号、分号或重定向符号,就可能执行意料之外的命令。比如你拼接 git commit -m "${userInput}",用户输进 "fix bug; rm -rf /",exec 就真会删根目录。
用 child_process.spawn 替代 exec 是基本底线
spawn 把命令和参数拆成数组传入,绕过 shell 解析层,天然免疫注入。但要注意:它不支持管道、重定向、通配符展开——这些得你自己处理或换方案。
- ✅ 正确:
spawn("git", ["commit", "-m", userInput])——userInput被当纯字符串传入 - ❌ 错误:
spawn("git commit -m " + userInput)—— 这其实还是走exec逻辑 - ⚠️ 注意:
spawn的cwd必须是绝对路径,相对路径可能因工作区切换失效
需要 shell 功能时,必须显式白名单 + 输入净化
比如你要支持 | 或 &&,就不能回避 shell。此时必须:先校验整个命令字符串是否匹配预设正则(如 ^git\s+status$|^npm\s+run\s+\w+$),再对每个参数单独做 shellEscape(Node.js 没内置,可用 shell-escape 包)。
- 别信
userInput.replace(/[^a-zA-Z0-9\s]/g, "")—— 空格和连字符也可能被滥用 - 别在插件里调用
sudo或apt类命令 —— 用户权限不可控,失败率高且风险爆炸 - 若必须运行用户脚本,强制要求其路径在工作区根目录下,且用
fs.realpath()校验不跨出该路径
权限与上下文隔离常被忽略
VSCode 插件默认以用户权限运行,能访问所有该用户可读文件。如果你的命令涉及读写配置、密钥或 .env,务必检查当前工作区是否启用 workspace.trust。未受信任的工作区里,应直接拒绝执行任何系统命令。
- 用
vscode.workspace.isTrusted判断,别只看vscode.workspace.rootPath是否存在 - 日志里记录每次命令调用的完整参数数组(不是拼接后的字符串),方便审计
- Windows 下避免用
cmd.exe /c,优先走pwsh.exe -Command或 WSL 的 bash —— 后者行为更可控


















