Skip to content

[audit] Quoted secret values with spaces are only partially redacted #19

Description

@jamiesun

问题

PR #18 新增的 audit redaction 对带空格的 quoted password/token 值只脱敏第一个空白前的片段,后续片段仍会写入 audit JSONL 的 commandoutcome.message。这会破坏审计日志“不记录 secret”的安全边界。

证据

  • Commit/PR: 2517a2efa26686db10f0c407bd71a7d50f1d7bb7 / feat(cli): add local audit trail #18
  • 文件路径: internal/app/audit.go
  • 相关 diff / CI / 测试信号:
    • feat(cli): add local audit trail #18 新增 sensitiveAssignmentRE / sensitiveFlagRE,二者的 value 捕获均使用非空白 token 范围:([^\s&;]+) / ([^\s]+)
    • redactSensitiveText 直接用这些正则替换,现有测试只覆盖了不含空格的假值。
    • 本地在 2026-06-20T23:33:12+08:00 使用假值复现:
go run ./cmd/sshx -h=192.0.2.1 --audit-output=<tmp> --json 'sudo rm -rf / password="alpha bravo" --token "charlie delta"'

生成的 audit JSONL 中仍包含 quoted value 的尾部片段:

"command":"sudo rm -rf / password=<redacted> bravo\" --token <redacted> delta\""

outcome.message 也包含相同的残留片段。

影响

受影响路径是默认开启的本地 audit trail。只要远程命令或错误消息中包含 password="... ..."--token "... ..." 等带空格的敏感值,audit 文件会保留敏感值的后半段。虽然复现使用的是假值,但真实命令中的 token、口令短语或带空格 secret 会被部分泄漏到 ~/.sshx/audit/sshx-YYYY-MM-DD.jsonl

最小修复方案

扩展 redaction 解析,至少覆盖 quoted assignment/flag values:

  • key="..." / key='...'
  • --token "..." / --token '...'
  • 保留现有 unquoted token 行为

避免引入 shell 执行或完整 shell parser;可以先用更明确的 quoted-value 正则在 unquoted 规则之前处理,并补齐单元测试。

验证建议

  • 新增 redactSensitiveText 单元测试,覆盖 quoted assignment、quoted flag、unquoted assignment、unquoted flag。
  • 运行 go test ./...
  • 手工复现上面的 blocked-command audit smoke,确认 JSONL 中不再出现 quoted value 的任何残留片段。

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-todoReady for automated agent implementationbugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions