问题
当前 --json 模式下,安全检查拦截危险命令时,stdout 的结构化结果仍会在 command 字段和 error 文本中原样回显命令参数。#20 已修复 audit JSONL 对 quoted secret-like 参数的脱敏,但同一条 blocked-command 路径的 CLI JSON 输出仍可能把这些参数写到调用方日志中。
证据
Commit/PR: be599110685892848b30a1d5400a40b5441f268f / test: cover state and audit contracts #23 ;相关修复 PR fix(audit): redact quoted secret values #20
文件路径: internal/app/app.go, internal/app/audit.go, internal/app/agentmode_test.go
相关 diff / CI / 测试信号:
internal/app/app.go 的 emitCommandJSON 直接设置 Command: config.Command,并在 execErr != nil 时设置 result.Error = execErr.Error()。
internal/app/audit.go 的 recordFailure / refresh 会通过 redactError / redactSensitiveText 脱敏 audit 事件;这说明 audit 面已经修复,但 JSON stdout 面没有复用同一脱敏逻辑。
internal/app/agentmode_test.go 新增/保留的 TestRun_BlockedCommandShortCircuits 只断言 error_kind=blocked、exit_code=-1、success=false,没有覆盖 sensitive argument redaction。
本地在 origin/main 临时 worktree 上运行 go test ./... 全部通过;同一 head 的 GitHub CI run 27876869243 和 CodeQL run 27876868845 均为 success。
使用假值复现:
go run ./cmd/sshx -h=192.0.2.1 --audit-output=<tmp> --json 'sudo rm -rf / password="<fake word pair>" --token "<fake word pair>"'
观察到 audit JSONL 已正确脱敏:
"command" :" sudo rm -rf / password=<redacted> --token <redacted>"
但 stdout JSON 仍包含未脱敏的 command 和 error 命令文本;复现中只使用假值,以下摘录已进一步替换为占位符:
{"command" :" sudo rm -rf / password=\" <fake-secret-fragment> <fake-secret-fragment>\" --token \" <fake-secret-fragment> <fake-secret-fragment>\" " ,"error_kind" :" blocked" ,"error" :" ... Command: sudo rm -rf / password=\" <fake-secret-fragment> <fake-secret-fragment>\" --token \" <fake-secret-fragment> <fake-secret-fragment>\" ..." }
影响
受影响路径是 agent/automation 常用的 --json 结构化输出。危险命令会在联网前被拦截,但如果命令行中同时包含 token、password、api key 等敏感参数,调用方保存 stdout JSON 时仍可能记录完整参数;这与 audit trail 已建立的 redaction 行为不一致。
最小修复方案
在 JSON 输出面复用现有脱敏逻辑:
emitCommandJSON 输出 command 时对 config.Command 做 redaction。
execErr 为 CommandBlockedError 或其它包含命令文本的错误时,对 execErr.Error() 做 redaction 后再写入 error。
保留非敏感命令的现有 JSON contract,避免改动 SSH 执行流程。
验证建议
新增 --json blocked-command 单元测试,输入 quoted assignment/flag fake values,断言 command 和 error 都不包含 fake value 的任一片段。
保留现有 audit redaction 测试,确认 audit JSONL 与 stdout JSON 两个输出面都脱敏。
运行 go test ./...。
问题
当前
--json模式下,安全检查拦截危险命令时,stdout 的结构化结果仍会在command字段和error文本中原样回显命令参数。#20 已修复 audit JSONL 对 quoted secret-like 参数的脱敏,但同一条 blocked-command 路径的 CLI JSON 输出仍可能把这些参数写到调用方日志中。证据
be599110685892848b30a1d5400a40b5441f268f/ test: cover state and audit contracts #23;相关修复 PR fix(audit): redact quoted secret values #20internal/app/app.go,internal/app/audit.go,internal/app/agentmode_test.gointernal/app/app.go的emitCommandJSON直接设置Command: config.Command,并在execErr != nil时设置result.Error = execErr.Error()。internal/app/audit.go的recordFailure/refresh会通过redactError/redactSensitiveText脱敏 audit 事件;这说明 audit 面已经修复,但 JSON stdout 面没有复用同一脱敏逻辑。internal/app/agentmode_test.go新增/保留的TestRun_BlockedCommandShortCircuits只断言error_kind=blocked、exit_code=-1、success=false,没有覆盖 sensitive argument redaction。origin/main临时 worktree 上运行go test ./...全部通过;同一 head 的 GitHubCIrun27876869243和CodeQLrun27876868845均为 success。使用假值复现:
观察到 audit JSONL 已正确脱敏:
但 stdout JSON 仍包含未脱敏的
command和error命令文本;复现中只使用假值,以下摘录已进一步替换为占位符:{"command":"sudo rm -rf / password=\"<fake-secret-fragment> <fake-secret-fragment>\" --token \"<fake-secret-fragment> <fake-secret-fragment>\"","error_kind":"blocked","error":"... Command: sudo rm -rf / password=\"<fake-secret-fragment> <fake-secret-fragment>\" --token \"<fake-secret-fragment> <fake-secret-fragment>\" ..."}影响
受影响路径是 agent/automation 常用的
--json结构化输出。危险命令会在联网前被拦截,但如果命令行中同时包含 token、password、api key 等敏感参数,调用方保存 stdout JSON 时仍可能记录完整参数;这与 audit trail 已建立的 redaction 行为不一致。最小修复方案
在 JSON 输出面复用现有脱敏逻辑:
emitCommandJSON输出command时对config.Command做 redaction。execErr为CommandBlockedError或其它包含命令文本的错误时,对execErr.Error()做 redaction 后再写入error。验证建议
--jsonblocked-command 单元测试,输入 quoted assignment/flag fake values,断言command和error都不包含 fake value 的任一片段。go test ./...。