Skip to content

[business-logic] command gate 注入规则按语法形式而非危险语义判定:bash/PowerShell 普通替换语法全量误报 Ask + bypass 降级放行被记为 denied 滚出虚假 SECURITY ESCALATION #4273

Description

@topcheer

文件与行号

  • internal/tool/command_gate.go:210-219(ASK 层五条裸符号注入规则)
  • internal/tool/run_command.go:840-850(bypass 降级放行 + Record("gate","ask-allowed"))
  • internal/tool/security_ledger.go:38(阈值 3)、:113("was denied N times" 横幅文案)
  • internal/tool/command_gate_test.go:136-161(把误报钉死为期望行为)

问题描述(独立复核确认,A-E 全部成立)

gate 的 40+ 条规则全部按命令内容定级(rm、sudo、curl|sh、DROP TABLE…),唯独注入段五条规则按 shell 语法原语判定:

  • \$\(、`.+`:bash 命令替换是普通组合语法,$(date) 无害
  • \$\{(218 行):desc "parameter expansion ${} can execute code" 在 bash 语义上错误——${var} 是纯参数展开,不执行命令;能执行代码的是 eval+展开组合,而规则表没有 eval 规则
  • 五条规则均未设 quotedInert:echo '${PATH}' 纯引号文本也触发 Ask
  • PowerShell 会话更严重:${tk}、$(...) 是 PS 日常变量/子表达式语法,gate 无 shell 区分,全量命中

冗余性:$(curl x|sh)→249 行、$(rm -rf x)→223/225 行、$(sudo x)→243 行均已独立覆盖——裸规则对"嵌套已知危险命令"零增量;唯一增量是嵌套 gate 本就不认识的命令,与 gate 内容判定哲学自相矛盾。

触发场景(用户实测截图 + 机制推演)

  1. PowerShell 会话 git push "https://oauth2:${tk}@..." → 命中 \$\{ → Ask → bypass 降级放行(命令实际执行成功)→ run_command.go:847 记为 denial → 同会话累计 186 次 → 每条后续命令前缀注入 "SECURITY ESCALATION: ... was denied 186 times ... stop varying the command" 的事实性错误指控
  2. bash 正常构建:go build -ldflags "-X main.v=${V}" 非 bypass 模式直接被 Ask 打断

预期 vs 实际

  • 预期:注入检测针对"替换体内嵌危险内容"(远程取回执行、解码到 shell);纯变量插值/命令替换放行
  • 实际:语法原语即 Ask;bypass 下高频虚假 escalation 注入 agent 上下文(狼来了效应稀释真实探测信号)

残余缺口(删裸规则需补偿)

base64 -d x | sh、echo $(printf 'xxx' | base64 -d) | sh 目前不被任何规则命中(249 行要求 curl/wget 前缀)——这是裸 $( 唯一真实价值的捕获面。

修复建议

  1. 规则层:删除/收窄五条裸符号规则;新增"解码到 shell":(?i)(base64|openssl\s+enc\s+-d|xxd\s+-r\s+-p)\b.*\|\s*(ba)?sh\b(结尾 \b 吸取 [business-logic] command_gate.go pipe-to-shell rule lacks word boundary - '| sha256sum' flagged as piping to shell #815 教训)
  2. ledger 语义层(独立修,优先级更高):Record 增加 outcome 区分 blocked 与 downgraded-allow;ask-allowed 不应触发 "was denied N times" 文案(或改为 "auto-allowed N times");阈值 3 对该路径过敏感
  3. 测试层:改写 TestCommandGate_InjectionPatternsAskNotBlock——echo $(whoami)、echo ${PATH}、cat <(echo hello) 改期望 Allow,新增 base64|sh 期望 Ask

严重程度

High(独立复核实评:无安全绕过/数据破坏,fail-safe 方向;但高频虚假 SECURITY ESCALATION 污染上下文 + 非 bypass 模式可用性损伤显著)

Activity

  1. topcheer commented on Oct 17, 2026

    @topcheer
    OwnerAuthor

    修复进展:PR #4274(draft)已开出,覆盖本 issue 的 ledger 语义层(ask-allowed 分组+中性文案+阈值10)与解码规则补偿(base64/openssl/xxd 解码到 shell → Ask)。规则表降级(五条裸符号规则→warning)由 #4238 承担,两者互补、已与 @ggcxf_reviewer 对齐叠加终态与验收清单。测试:zz_issue4273_test.go 5 组钉死 + zz_issue3282_test.go 适配,全包 go test 绿。

  2. topcheer commented on Oct 17, 2026

    @topcheer
    OwnerAuthor

    又一个活体实证(用户 mac mini TUI,8ef147bf5 版本,bypass 模式):k8s 常规运维链(kubectl exec mysql pod 写 app_settings/dep_upgrades)被弹 'Bypass mode approval'。根因:命令含 MySQL 标识符反引号 `key`(app_settings(`key`,value,...)),裸反引号规则 `.+` 误判为 shell 命令替换。实测复现:gate.Check → ask=true 'backtick command substitution';permission 层对 Bash 工具本来就 allow(#4290)。PR #4291 分支同命令实测 allow(behavior=0)——该 PR 精确覆盖此场景,合入发版后消失。

  3. added a commit that references this issue on Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions