Audit and sanitize untrusted ANSI terminal output in pure MoonBit
moon add SongYZZZ/ansi-guardimport {
"SongYZZZ/ansi-guard" @ansi_guard,
}| 输入类型 | 默认处理 | 风险 |
|---|---|---|
| CSI SGR 颜色/样式 | 删除,可按策略保留 | 低 |
| 光标移动、清屏、擦除 | 删除并记录 | 日志伪造 |
| OSC 8 超链接 | 删除并记录 | 显示文本与真实链接不一致 |
| OSC 0/2 标题修改 | 删除并记录 | 界面欺骗 |
| OSC 52 剪贴板写入 | 删除并标记为危险 | 修改用户剪贴板 |
| DCS、APC、PM | 删除并标记为危险 | 终端特定行为 |
| 回车、退格 | 删除并记录 | 覆盖可见日志 |
| 未终止或超长序列 | 截断并标记为危险 | 解析绕过或资源消耗 |
| 括号粘贴、鼠标、焦点、备用屏幕模式 | 删除并记录 | 改变后续输入或隐藏输出 |
| 终端查询和窗口操作 | 删除并记录 | 触发终端响应或改变窗口状态 |
| 工作目录、通知、Shell Integration | 删除并记录 | 路径泄露、通知欺骗或提示符伪造 |
| iTerm2 文件/图片传输 | 删除并标记为危险 | 向终端传输攻击者控制的数据 |
let result = @ansi_guard.scan(
"build: \u{1b}[31mFAILED\u{1b}[0m\u{1b}]52;c;SGVsbG8=\u{07}",
)
println(result.text())
// build: FAILED
println(result.risk_level())
// high
println(result.audit_report())let scanner = @ansi_guard.StreamScanner::new(
policy=@ansi_guard.Policy::agent(),
)
let session = @ansi_guard.AuditSession::new()
session.record(scanner.feed("tool: \u{1b}]52;c;"))
session.record(scanner.feed("secret"))
session.record(scanner.feed("\u{07}done"))
session.record(scanner.finish())
let result = session.result()
println(result.json_report_with(@ansi_guard.ReportPolicy::redacted()))let safe = @ansi_guard.sanitize(untrusted_output)let result = @ansi_guard.scan_with_policy(
trusted_output,
@ansi_guard.Policy::styled(),
)moon check
moon build
moon test
moon run cmd/mainmoon run cmd/audit -- --escaped "build ok\e]52;c;secret\a done"| 案例 | 覆盖能力 |
|---|---|
| 彩色构建日志 | CSI SGR 样式序列 |
| 剪贴板写入 | OSC 52 |
| 隐藏超链接 | OSC 8 |
| 窗口标题伪装 | OSC 0/2 |
| 光标与清屏改写 | CSI 光标移动、擦除 |
| 回车与退格改写 | C0 控制字符 |
| 私有终端负载 | DCS、APC、PM |
| 截断序列 | 未终止控制序列 |
| 策略对比 | strict/styled |
moon run examples/ci-gate
moon run examples/agent-output
moon run examples/stream-audit
moon run examples/policy-gatepub struct Finding {
kind : FindingKind
severity : Severity
offset : Int
sequence : String
message : String
} derive(Eq, Debug)pub(all) enum FindingKind {
StyleSequence
CursorControl
ScreenControl
ModeChange
TerminalQuery
WindowControl
TitleChange
Hyperlink
ClipboardWrite
WorkingDirectory
Notification
ShellIntegration
FileTransfer
PaletteChange
CharacterSet
DeviceControl
ControlCharacter
TruncatedSequence
OversizedSequence
UnknownEscape
} derive(Eq, Debug)pub struct GatePolicy {
block_on_dangerous : Bool
block_score : Int
review_score : Int
review_finding_count : Int
blocked_kinds : Array[FindingKind]
} derive(Eq, Debug)fn GatePolicy::new(block_on_dangerous? : Bool, block_score? : Int, review_score? : Int, review_finding_count? : Int, blocked_kinds? : Array[FindingKind]) -> GatePolicyfn ReportPolicy::new(include_safe_text? : Bool, include_sequences? : Bool, safe_text_limit? : Int, sequence_limit? : Int) -> ReportPolicyfn sanitize(input : String) -> StringInstall
Download zipAudit and sanitize untrusted ANSI terminal output in pure MoonBit