问题概述
Bash 工具会把 && 右侧未执行命令的特殊退出码语义,错误地套用到整条命令上。当前置命令以 1 失败、右侧恰好是 rg / grep / diff / test / find 时,真实失败可能被解释成“无匹配”等非错误结果。
这不是安全问题,而是日常使用中的命令执行结果误判。
严重度
较严重(High)
- 会把真实的测试、构建或业务命令失败静默转成成功 tool result。
- Claude 可能基于一个根本没有执行的后续命令继续推理或修改代码。
- 只要前置程序以退出码 1 失败即可稳定触发,常见测试/lint/CLI 均可能使用该退出码。
环境
- 代码版本:
3bb6b5746238c418138eb96d57765d79012edd96
- Bun:
1.3.13
- 系统:
Linux 5.15.0-186-generic x86_64
- 源码方式运行
稳定复现
在仓库根目录创建 repro.ts:
import { spawnSync } from 'node:child_process'
import { interpretCommandResult } from './packages/builtin-tools/src/tools/BashTool/commandSemantics.ts'
const commands = [
"node -e 'process.exit(1)' && rg needle /dev/null",
"node -e 'process.exit(1)' && grep needle /dev/null",
"node -e 'process.exit(1)' && diff /dev/null /dev/null",
"node -e 'process.exit(1)' && test -e /definitely-not-present",
"node -e 'process.exit(1)' && find /dev/null -name needle",
]
for (const command of commands) {
const run = spawnSync('bash', ['-lc', command], { encoding: 'utf8' })
console.log({
command,
exitCode: run.status,
interpretation: interpretCommandResult(
command,
run.status ?? 1,
run.stdout,
run.stderr,
),
})
}
运行 bun repro.ts,稳定输出:
node ... && rg ... -> exitCode=1, isError=false, "No matches found"
node ... && grep ... -> exitCode=1, isError=false, "No matches found"
node ... && diff ... -> exitCode=1, isError=false, "Files differ"
node ... && test ... -> exitCode=1, isError=false, "Condition is false"
node ... && find ... -> exitCode=1, isError=false, "Some directories were inaccessible"
这些命令中的 node 已经以 1 退出,因此 && 右侧命令根本没有执行。控制组 true && rg needle /dev/null 和 printf x | rg needle 的退出码 1 确实来自 rg,此时“无匹配”语义合理。
实际行为
interpretCommandResult() 返回 isError: false。随后 BashTool 不抛出 ShellError,可能给模型一个空的成功结果。
预期行为
当无法证明 && 最后一个语法段实际执行时,应保守使用默认语义;非零退出码应保持为错误。
根因
packages/builtin-tools/src/tools/BashTool/commandSemantics.ts 的 heuristicallyExtractBaseCommand() 使用 splitCommand_DEPRECATED() 丢弃控制运算符后,无条件选择最后一个语法段。它只知道整条命令的聚合退出码,不知道最后实际执行的是哪个段。
packages/builtin-tools/src/tools/BashTool/BashTool.tsx 随后依据该解释结果决定是否抛出 ShellError,因此误判会进入模型可见结果。
建议修复
- 用保留控制运算符的解析结果识别顶层
&&。
- 在执行器尚未返回“最后实际执行命令/各段状态”前,对存在
&& 的命令回退到默认退出码语义。
- 保留简单
rg、管道以及纯 || 的现有语义。
- 增加
rg、diff 等短路回归测试,以及 false || rg 控制组。
查重
已检索开放/关闭 issue 和全部 PR,关键词包括 commandSemantics、short circuit、rg exit code、No matches found,未发现同因问题。
问题概述
Bash 工具会把
&&右侧未执行命令的特殊退出码语义,错误地套用到整条命令上。当前置命令以 1 失败、右侧恰好是rg/grep/diff/test/find时,真实失败可能被解释成“无匹配”等非错误结果。这不是安全问题,而是日常使用中的命令执行结果误判。
严重度
较严重(High)
环境
3bb6b5746238c418138eb96d57765d79012edd961.3.13Linux 5.15.0-186-generic x86_64稳定复现
在仓库根目录创建
repro.ts:运行
bun repro.ts,稳定输出:这些命令中的
node已经以 1 退出,因此&&右侧命令根本没有执行。控制组true && rg needle /dev/null和printf x | rg needle的退出码 1 确实来自rg,此时“无匹配”语义合理。实际行为
interpretCommandResult()返回isError: false。随后 BashTool 不抛出ShellError,可能给模型一个空的成功结果。预期行为
当无法证明
&&最后一个语法段实际执行时,应保守使用默认语义;非零退出码应保持为错误。根因
packages/builtin-tools/src/tools/BashTool/commandSemantics.ts的heuristicallyExtractBaseCommand()使用splitCommand_DEPRECATED()丢弃控制运算符后,无条件选择最后一个语法段。它只知道整条命令的聚合退出码,不知道最后实际执行的是哪个段。packages/builtin-tools/src/tools/BashTool/BashTool.tsx随后依据该解释结果决定是否抛出ShellError,因此误判会进入模型可见结果。建议修复
&&。&&的命令回退到默认退出码语义。rg、管道以及纯||的现有语义。rg、diff等短路回归测试,以及false || rg控制组。查重
已检索开放/关闭 issue 和全部 PR,关键词包括
commandSemantics、short circuit、rg exit code、No matches found,未发现同因问题。