|
| 1 | +# Tool Script Safety Guard 设计文档 |
| 2 | + |
| 3 | +本文档说明 Tool Script Safety Guard 的请求处理流程,以及遇到不同风险程度命令时的决策和执行结果。 |
| 4 | + |
| 5 | +## 设计目标 |
| 6 | + |
| 7 | +Tool、Skill、MCP Tool 和 CodeExecutor 都可能执行脚本、shell 命令、外部进程或网络请求。Safety Guard 的目标是在真实执行前完成静态扫描和策略判断,把明显危险的请求拦截在执行边界外,并为不确定请求提供人工复核、审计和 telemetry 信息。 |
| 8 | + |
| 9 | +实现保持向后兼容:`BashTool` 和 `UnsafeLocalCodeExecutor` 默认不改变历史行为,只有显式设置 `enable_safety_guard=True` 后才启用扫描。`deny` 默认阻断执行;`needs_human_review` 默认记录但不阻断,设置 `block_on_review=True` 后也会阻断。 |
| 10 | + |
| 11 | +## 请求处理流程 |
| 12 | + |
| 13 | +```text |
| 14 | +Tool / Skill / MCP Tool / CodeExecutor request |
| 15 | + | |
| 16 | + v |
| 17 | +提取待执行内容 |
| 18 | +script / code / command / cmd / code_blocks |
| 19 | +language / command_args / cwd / env / tool_metadata |
| 20 | + | |
| 21 | + v |
| 22 | +ToolScriptScanRequest |
| 23 | + | |
| 24 | + v |
| 25 | +ToolScriptSafetyScanner.scan() |
| 26 | + | |
| 27 | + +--> 语言归一化: python / bash / unknown |
| 28 | + +--> 脱敏检测: script 和 env 中的 key/token/password/private_key |
| 29 | + +--> Python AST 规则: open、Path、subprocess、os.system、requests、socket、eval、while True |
| 30 | + +--> Bash 规则: rm、curl、wget、管道、重定向、命令替换、依赖安装、sudo、sleep、fork bomb |
| 31 | + +--> 执行上下文规则: cwd、timeout、max_output_bytes、command_args |
| 32 | + | |
| 33 | + v |
| 34 | +命中 RiskFinding 列表 |
| 35 | + | |
| 36 | + v |
| 37 | +聚合最终决策 |
| 38 | +deny > needs_human_review > allow |
| 39 | + | |
| 40 | + v |
| 41 | +SafetyReport + AuditEvent + tool.safety.* telemetry |
| 42 | + | |
| 43 | + v |
| 44 | +执行边界判断 |
| 45 | +allow: 执行 |
| 46 | +needs_human_review: 默认执行并记录;strict 模式阻断 |
| 47 | +deny: 阻断 |
| 48 | +``` |
| 49 | + |
| 50 | +## 决策聚合规则 |
| 51 | + |
| 52 | +每条规则会输出 `RiskFinding`,字段包括 `rule_id`、`risk_type`、`risk_level`、`decision`、`evidence` 和 `recommendation`。最终 `SafetyReport` 采用保守聚合: |
| 53 | + |
| 54 | +| 命中情况 | 最终 decision | risk_level | 默认 blocked | |
| 55 | +| --- | --- | --- | --- | |
| 56 | +| 没有 finding | `allow` | `none` | `false` | |
| 57 | +| 只有低风险或无阻断 finding | `allow` | `low` 或 `none` | `false` | |
| 58 | +| 任意 finding 为 `needs_human_review`,且没有 `deny` | `needs_human_review` | 命中项最高风险 | `false` | |
| 59 | +| 任意 finding 为 `deny` | `deny` | 命中项最高风险 | `true` | |
| 60 | + |
| 61 | +`ToolSafetyGuard` 和 `ToolSafetyFilter` 会在生成报告后调用 `report.set_blocked(...)`。默认只阻断 `deny`;当 `block_on_review=True` 时,`needs_human_review` 也会阻断。 |
| 62 | + |
| 63 | +## 不同风险命令的处理结果 |
| 64 | + |
| 65 | +| 风险程度 | 示例命令或脚本 | 典型规则 | decision | 默认执行结果 | strict 模式结果 | |
| 66 | +| --- | --- | --- | --- | --- | --- | |
| 67 | +| 无风险 | `pwd`、`ls`、`cat README.md` | 无命中 | `allow` | 继续执行 | 继续执行 | |
| 68 | +| 低风险 | `echo hello`、读取普通工作区文件 | 无阻断 finding | `allow` | 继续执行并记录报告 | 继续执行并记录报告 | |
| 69 | +| 中等风险 | `python -c ...`、`eval(...)`、`while True`、超出 `max_timeout_seconds` | `PY_DYNAMIC_CODE_EXECUTION`、`PY_INFINITE_LOOP`、`RESOURCE_TIMEOUT_LIMIT_EXCEEDED` | `needs_human_review` | 默认继续执行,但报告、审计和 telemetry 标记人工复核 | 阻断执行 | |
| 70 | +| 高风险 | 非白名单域名外连、动态 shell 命令、`socket.socket()`、复杂管道/重定向 | `NETWORK_NON_WHITELIST_DOMAIN`、`PY_SHELL_INJECTION_RISK`、`BASH_SHELL_FEATURE_REVIEW` | `deny` 或 `needs_human_review` | `deny` 阻断;人工复核项默认记录 | 人工复核项也阻断 | |
| 71 | +| 严重风险 | `rm -rf /`、访问 `.env`/`~/.ssh`、私钥字面量、`curl ... \| sh`、`sudo`、fork bomb | `BASH_RECURSIVE_DELETE`、`FILE_SECRET_PATH_ACCESS`、`SENSITIVE_PRIVATE_KEY_LITERAL`、`BASH_PRIVILEGE_ESCALATION`、`BASH_FORK_BOMB` | `deny` | 阻断执行 | 阻断执行 | |
| 72 | + |
| 73 | +处理结果以结构化报告返回。例如被拦截时,调用方不会执行真实工具逻辑,而是收到 `safety_report`,其中 `blocked=true`、`decision=deny`,并包含命中的 `rule_id`、证据和修复建议。 |
| 74 | + |
| 75 | +## 接入点语义 |
| 76 | + |
| 77 | +### BashTool |
| 78 | + |
| 79 | +`BashTool(enable_safety_guard=True)` 会在执行 shell 命令前构造 `ToolScriptScanRequest`。扫描通过时继续执行原有 bash 逻辑;命中 `deny` 时返回带 `safety_report` 的阻断结果;命中 `needs_human_review` 时默认继续执行并把报告附加到结果中。 |
| 80 | + |
| 81 | +### UnsafeLocalCodeExecutor |
| 82 | + |
| 83 | +`UnsafeLocalCodeExecutor(enable_safety_guard=True)` 会在本地 Python 代码执行前扫描代码块和执行元数据。`deny` 会在执行前阻断,避免危险代码进入本地执行器;`needs_human_review` 的默认和 strict 行为与 `BashTool` 一致。 |
| 84 | + |
| 85 | +### ToolSafetyGuard |
| 86 | + |
| 87 | +`ToolSafetyGuard.run(request, execute)` 是通用 wrapper。它先扫描、写审计、写 telemetry,再根据 `blocked` 决定是否调用 `execute()`。被阻断时返回 `GuardedExecutionResult(blocked=True)`。 |
| 88 | + |
| 89 | +### ToolSafetyFilter |
| 90 | + |
| 91 | +`ToolSafetyFilter` 用于 tRPC-Agent Filter 链路。它从请求字典中提取 `script`、`code`、`command`、`cmd`、`python_code`、`bash_code` 或 `code_blocks`。如果阻断,设置 `rsp.is_continue=False` 和 `rsp.error=PermissionError(...)`;否则把 `SafetyReport` 放入 `rsp.rsp` 供后续链路消费。 |
| 92 | + |
| 93 | +## Policy 配置如何影响结果 |
| 94 | + |
| 95 | +策略文件 `examples/tool_safety/tool_safety_policy.yaml` 控制扫描结果: |
| 96 | + |
| 97 | +| 配置项 | 影响 | |
| 98 | +| --- | --- | |
| 99 | +| `allowed_domains` | URL、requests/httpx/aiohttp/curl/wget 目标域名不在白名单时触发网络风险 | |
| 100 | +| `allowed_commands` | bash 命令不在允许列表时进入人工复核 | |
| 101 | +| `denied_paths` | `.env`、`~/.ssh`、私钥、系统账号文件等路径直接触发高危或严重风险 | |
| 102 | +| `max_timeout_seconds` | 请求 timeout 超预算时触发 `needs_human_review` | |
| 103 | +| `max_output_bytes` | 请求输出大小超预算时触发 `needs_human_review` | |
| 104 | +| `deny_dependency_install` | `pip install`、`npm install`、`apt install` 等依赖安装可直接拒绝 | |
| 105 | +| `deny_privilege_escalation` | `sudo`、特权操作等可直接拒绝 | |
| 106 | +| `review_unknown_network` | 动态 URL 或无法静态确认域名时进入人工复核 | |
| 107 | +| `review_process_execution` | `subprocess`、`os.system` 等进程执行进入人工复核 | |
| 108 | +| `review_shell_features` | 管道、重定向、命令替换、后台执行等 shell 特性进入人工复核 | |
| 109 | + |
| 110 | +启用 strict policy validation 时,未知字段、错误类型和负数限制值会在加载阶段报错,避免策略拼写错误导致安全配置静默失效。 |
| 111 | + |
| 112 | +## 审计和监控 |
| 113 | + |
| 114 | +每次扫描都会生成 `SafetyReport`。配置 `audit_log_path` 后会追加 JSONL `AuditEvent`,字段包含 `scan_id`、`tool_name`、`decision`、`risk_level`、`rule_ids`、`elapsed_ms`、`sanitized` 和 `blocked`。 |
| 115 | + |
| 116 | +同时预留 OpenTelemetry 兼容字段: |
| 117 | + |
| 118 | +- `tool.safety.scan_id` |
| 119 | +- `tool.safety.decision` |
| 120 | +- `tool.safety.risk_level` |
| 121 | +- `tool.safety.rule_id` |
| 122 | +- `tool.safety.blocked` |
| 123 | +- `tool.safety.sanitized` |
| 124 | +- `tool.safety.tool_name` |
| 125 | +- `tool.safety.duration_ms` |
| 126 | + |
| 127 | +这些字段只用于观测,不会改变扫描决策或执行结果。 |
| 128 | + |
| 129 | +## 安全边界和限制 |
| 130 | + |
| 131 | +Safety Guard 是执行前静态治理层,不替代沙箱、最小权限、网络隔离和运行时资源限制。它主要拦截确定性高危行为,并把不确定行为降级到人工复核。对于混淆脚本、运行时拼接、远程下载后执行、间接导入和复杂数据流,仍需要结合 Container/Cube 沙箱、出网控制和运行时审计。 |
0 commit comments