# OpenClaw Evaluation 文档升级报告

**日期**: 2026-04-25  
**范围**: `docs/adr/0003-openclaw-comprehensive-evaluation.md` 与 `docs/specs/openclaw-evaluation.md`  
**配套审计文件**: `audit-results.md`

## 结论

ADR-0003 的方向成立：Judge 抽象、server-audit 独立化、adapter 注册表、多轮测试、综合评估 CLI 都是当前 AgentSec 从 v0.1.0 升级到 v0.2.0 的合理主线。

但完整规格在进入实现前需要一次收敛。当前主要问题集中在五类：

1. 外部威胁情报与 CVE 数字缺少可追溯来源，且部分数字与公开资料不一致。
2. 新规格与当前代码接口存在阻塞级不匹配，尤其是 `Judge` 返回类型、`AgentResponse` 字段、OpenClaw adapter 端点和 `TestCase.attack` 必填约束。
3. server-audit 的安全边界写得过粗，SSH 命令白名单、路径范围、证据脱敏、授权文件位置都需要明确。
4. 多轮、记忆投毒、间接注入 fixture 缺少状态隔离和清理机制，容易污染真实 OpenClaw 实例。
5. 报告与评分口径会被测试数量和重复 finding 放大，需要归一化、去重和 `skipped/not_applicable` 状态。

建议 ADR 保持“提议”状态；规格先完成 P0/P1 修改后再进入代码实现。

## 升级优先级

| 优先级 | 升级项 | 目标结果 |
|---|---|---|
| P0 | 补充威胁情报来源表 | 每个 CVE、暴露规模、ClawHavoc 数字都有来源、日期、可信度和更新时间 |
| P0 | 收敛核心数据契约 | `JudgeVerdict`、`TestResult`、`AgentResponse`、`Observation`、`Assertion` 字段稳定 |
| P0 | 修正 adapter 设计 | OpenClaw adapter 明确覆写 `/v1/chat/completions` 端点，字段使用现有 `content` 而非 `text` |
| P0 | 强化授权与审计安全 | 明确 `AUTHORIZATION.txt` 在 evaluator 侧还是 target 侧；签名、过期、host/scope 校验为强制项 |
| P0 | SSH policy 细化 | 从命令名白名单升级为参数语法、路径 allowlist、输出大小限制和脱敏策略 |
| P1 | 多轮隔离与清理 | 定义 session namespace、memory reset、测试后清理和破坏性用例默认跳过机制 |
| P1 | 评分模型归一化 | 按类别或唯一 finding 计分，避免 135 条远程用例或重复 server findings 直接压到 0 分 |
| P1 | 接入 OpenClaw 原生审计 | 将 `openclaw security audit --json` 作为优先数据源之一，而不是完全重复实现 |
| P2 | 任务拆分重估 | ADR 的 3-4 周与规格的 5.5 周不一致；建议以 5.5-6.5 周作为 v0.2.0 实施基线 |

## 推荐文档修改

### 1. 新增“威胁情报基线”章节

在规格第 2 节前加入来源表：

| 条目 | 当前写法 | 建议 |
|---|---|---|
| 安全公告数量 | 137+ | 标明来源与统计口径；若采用 GitHub Advisory / NVD / 第三方汇总，分别列出 |
| 暴露实例数量 | ADR 写 22 万 | 需要核验；当前抽样公开来源出现 40,214、63,026、135,000+ 等不同数字 |
| ClawHavoc | 1,184+ | 保留，但区分“历史识别”“仍可访问”“下载量” |
| CVE 列表 | 只列 3 个 | 追加 patched version、CVSS、利用前提、评估用例映射 |

建议字段：

```yaml
threat_intel:
  source: github_advisory
  url: https://github.com/advisories/GHSA-g8p2-7wf7-98mq
  observed_at: 2026-04-25
  claim: CVE-2026-25253 patched in 2026.1.29
  confidence: high
  mapped_tests: [auth-ws-001, exposure-003]
```

### 2. 固定核心模型

当前规格把 `JudgeVerdict` 与 `TestResult` 分开是正确方向，但要明确 runner 的职责：Judge 只给 verdict，runner 负责组装结果。

```python
class JudgeVerdict(BaseModel):
    passed: bool
    reasoning: str
    evidence: dict = {}
    judge_type: Literal["llm", "deterministic", "hybrid"]

class Observation(BaseModel):
    response: AgentResponse
    outbound_requests: list[dict] = []
    fixture_events: list[dict] = []
    tool_events: list[dict] = []

class TestResult(BaseModel):
    test_id: str
    category: str
    severity: Severity
    status: Literal["passed", "failed", "skipped", "error"]
    verdict: JudgeVerdict | None = None
    observations: list[Observation] = []
    latency_ms: float = 0.0
```

这样 deterministic/hybrid judge 可以读取 HTTP raw、fixture 回调、出站请求、工具事件，而不是只拿到字符串响应。

### 3. 修正 OpenClaw Gateway Adapter 规格

当前 `HttpAgentAdapter.send()` 固定 POST `{base_url}/chat`，而 OpenClaw 需要 `/v1/chat/completions`。规格应写明二选一：

1. 给 `HttpAgentAdapter` 增加 `path` 属性。
2. 或让 `OpenClawGatewayAdapter` 覆写 `send()`。

同时 `AgentResponse` 当前字段是 `content`，不是 `text`。规格示例应改为：

```python
return AgentResponse(
    content=data["choices"][0]["message"]["content"],
    raw=data,
)
```

### 4. 收敛 YAML 与 Assertion Schema

`attack` 现在是必填字段；多轮 `turns` 要落地，必须先修改 Pydantic 校验：

```python
class TestCase(BaseModel):
    attack: str | None = None
    turns: list[Turn] | None = None

    @model_validator(mode="after")
    def require_attack_or_turns(self):
        if bool(self.attack) == bool(self.turns):
            raise ValueError("exactly one of attack or turns is required")
        return self
```

`assertions` 也要列成枚举，不要只靠示例：

| Assertion type | 需要输入 | 依赖观测 |
|---|---|---|
| `response_not_contains_pattern` | `pattern` | response content |
| `response_status_in` | `statuses` | HTTP raw/status |
| `json_path_equals` | `path`, `value` | raw JSON |
| `outbound_request_not_to` | `target` | fixture/proxy events |
| `file_not_created` | `path` | server-audit or sandbox probe |
| `config_key_not_changed` | `key`, `forbidden_value` | pre/post config snapshot |

### 5. 加固 server-audit 安全模型

命令名白名单不够安全。`find` 可带 `-exec`，`openssl` 可发起网络连接，`grep -R` 与 `cat` 可读取超范围敏感文件。建议升级为：

```yaml
ssh_policy:
  allowed_paths:
    - ~/.openclaw/
    - /tmp/openclaw/
    - /etc/systemd/system/openclaw*.service
  max_output_bytes: 1048576
  redact_patterns:
    - "(?i)(api[_-]?key|token|secret|password)=([^\\s]+)"
  commands:
    stat:
      args: ["--format", "%a %U %G %n", "<allowed_path>"]
    find:
      forbidden_args: ["-exec", "-delete", "-ok"]
    openssl:
      mode: "local_cert_parse_only"
```

并要求所有 evidence 在进入 report 前统一走脱敏器。

### 6. 授权确认改为强制可验证

ADR 写“目标项目目录下存在 `AUTHORIZATION.txt`”，规格配置写 `./AUTHORIZATION.txt`。这两个位置不同，必须统一。建议：

1. evaluator 侧必须提供 consent file。
2. target 侧可选要求存在同名 consent marker，作为双向确认。
3. `signature` 不应是“可选”；若暂不做签名，应明确 `signature: null` 且标记为低保证模式。
4. 校验 `target_host`、`scope`、`valid_until`、操作者身份、报告输出路径。

### 7. 报告和评分改为可解释模型

建议每个类别先算通过率，再乘严重度权重；server-audit 按唯一 finding 指纹计分。

```text
remote_score = sum(category_score * category_weight)
server_score = 100 - sum(unique_finding_penalty)
combined = remote_score * remote_weight + server_score * server_weight
```

新增状态：

```text
passed | failed | skipped | error | not_applicable
```

否则某个类别用例多或某个检查产出重复 finding 时，综合分会失真。

## 推荐 v0.2.0 任务拆分

| 阶段 | 内容 | 退出标准 | 估算 |
|---|---|---|---|
| 0. 规格收敛 | 完成 P0 文档修改、来源表、数据契约 | ADR/Spec 无阻塞矛盾 | 0.5 周 |
| A. 模型与 Judge | `Judge` ABC、`JudgeVerdict`、多轮 `TestCase`、loader 兼容 | 现有 11 条用例无改动可跑 | 1 周 |
| B. Adapter 与观测 | registry、OpenClaw adapter、fixture server、Observation | 可采集 response 与 fixture events | 1 周 |
| C. 远程测试集 | 10 类用例、assertion schema、hybrid judge | P0/P1 类别至少有代表性用例 | 1 周 |
| D. server-audit MVP | native audit ingestion、SSH policy、4 个 P0 checks | 只读、安全、可生成 findings | 1 周 |
| E. server-audit 完整 | 9 类 checks、IOC/CVE 数据库、OS 抽象 | Linux/macOS 路径分支清晰 | 1.5 周 |
| F. 报告与 CLI | `evaluate`、JSON/Markdown、评分、授权 gate | 输出目录结构稳定，可接 CI | 0.5 周 |
| G. 集成回归 | mock OpenClaw、端到端、旧套件回归 | CI 通过，示例报告生成 | 0.5 周 |

总估算建议改为 6 周左右。若要压到 4 周，应砍掉跨渠道、多目标、完整 IOC 自动化和部分 P1 checks。

## 外部核验来源

本次审阅对近期 OpenClaw 安全事实做了抽样核验。建议后续在规格中固定来源表，而不是把数字直接写死在正文里。

- GitHub Advisory: CVE-2026-25253 / GHSA-g8p2-7wf7-98mq, patched in 2026.1.29: <https://github.com/advisories/GHSA-g8p2-7wf7-98mq>
- NVD: CVE-2026-41361 SSRF IPv6 bypass: <https://nvd.nist.gov/vuln/detail/CVE-2026-41361>
- RedPacket Security: CVE-2026-41349 consent bypass summary: <https://www.redpacketsecurity.com/cve-alert-cve-2026-41349-openclaw-openclaw/>
- GitHub Advisory: local plugin/hook install arbitrary code execution, patched in 2026.3.24: <https://github.com/openclaw/openclaw/security/advisories/GHSA-m3mh-3mpg-37hw>
- GitHub Advisory: browser upload path traversal / local file read, CVE-2026-26329: <https://github.com/advisories/GHSA-cv7m-c9jx-vg7q>
- OpenClaw Security Guide and native audit command: <https://docs.openclaw.ai/gateway/security>
- OpenClaw CLI security audit JSON output: <https://docs.openclaw.ai/cli/security>
- ClawHavoc 1,184 malicious skills report: <https://cyberpress.org/clawhavoc-poisons-openclaws-clawhub-with-1184-malicious-skills/>
- SecurityScorecard exposure figures as reported by TechRadar: <https://www.techradar.com/pro/security/the-math-is-simple-openclaw-trojan-horse-ai-agents-give-hackers-full-control-of-28-000-systems>
