# ZCLAW 全面项目审计报告 **日期**: 2026-03-30 **版本**: v0.8.0 **审计范围**: 系统架构、代码质量、性能表现、安全状况、业务功能、用户体验 --- ## 执行摘要 ### 整体健康评分: 6.5/10 ZCLAW 在快速迭代后展现出坚实的核心架构(清晰的 Crate 分层、零 `unsafe`、零 `todo!()`),但在安全防护、连接管理和前端健壮性方面存在显著缺陷。 | 维度 | 评分 | 关键发现数 | |------|------|-----------| | 架构健康度 | 7.5/10 | 15 项 | | 性能与稳定性 | 5.5/10 | 14 项 | | 安全审计 | 5.0/10 | 17 项 | | UX/功能完整性 | 6.5/10 | 12 项 | | **合计** | | **58 项** | ### 严重级别分布 | 级别 | 数量 | 说明 | |------|------|------| | Critical | 6 | 阻塞级,必须立即修复 | | High | 12 | 高风险,本迭代内修复 | | Medium | 22 | 中等风险,下迭代修复 | | Low | 18 | 低风险,纳入待办 | ### 推荐立即行动项 1. **SEC-1**: `saas-config.toml` 含数据库密码且被 Git 追踪 → `git rm --cached` 2. **FEAT-01**: `kernel.rs:444` multi-agent 编译错误 → 修改变量名 3. **RATE-1**: 公共认证端点无速率限制 → 添加限制 4. **CW-1**: 15s TimeoutLayer 中断 SSE 流 → 排除 relay 路由 5. **CRYPTO-1**: Provider API 密钥明文存储在数据库 → 启用加密 6. **UX-01**: Admin V2 无 Error Boundary → 添加全局错误边界 --- ## 架构依赖图 ```mermaid graph TD TYPES[zclaw-types
L0: 基础类型] --> MEMORY[zclaw-memory
L1: 存储层] TYPES --> GROWTH[zclaw-growth
L1: 成长系统] TYPES --> SKILLS[zclaw-skills
L2: 技能系统] TYPES --> PROTOCOLS[zclaw-protocols
L2: 协议支持] MEMORY --> RUNTIME[zclaw-runtime
L2: 运行时] GROWTH --> RUNTIME TYPES --> RUNTIME RUNTIME --> HANDS[zclaw-hands
L2: 自主能力] TYPES --> HANDS RUNTIME --> KERNEL[zclaw-kernel
L3: 核心协调] MEMORY --> KERNEL PROTOCOLS --> KERNEL HANDS --> KERNEL SKILLS --> KERNEL TYPES --> PIPELINE[zclaw-pipeline
L2: 工作流] RUNTIME --> PIPELINE KERNEL --> PIPELINE SKILLS --> PIPELINE HANDS --> PIPELINE KERNEL --> DESKTOP[desktop/src-tauri
L4: 桌面应用] SKILLS --> DESKTOP HANDS --> DESKTOP PROTOCOLS --> DESKTOP MEMORY --> DESKTOP RUNTIME --> DESKTOP PIPELINE --> DESKTOP GROWTH --> DESKTOP TYPES --> SAAS[zclaw-saas
ISO: SaaS 后端] PIPELINE -.->|向上依赖
违规| KERNEL DESKTOP -.->|绕过抽象层
直接依赖| MEMORY DESKTOP -.->|绕过抽象层| RUNTIME style PIPELINE fill:#fff3cd style DESKTOP fill:#fff3cd ``` **图例**: 黄色节点表示存在架构违规 --- ## 维度 1:架构健康度 ### 1.1 Crate 分层合规性 **整体评价**: 层次清晰,无循环依赖,但存在 2 处违规。 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | LAYER-01 | `zclaw-pipeline`(L2) 向上依赖 `zclaw-kernel`(L3) | High | `crates/zclaw-pipeline/Cargo.toml:28` | | LAYER-02 | `zclaw-hands` 和 `zclaw-runtime` 同层互相依赖 | Medium | `crates/zclaw-hands/Cargo.toml:12` | | LAYER-03 | `desktop/src-tauri` 直接导入 L1/L2 crate 绕过 kernel 抽象 | Medium | `desktop/src-tauri/Cargo.toml:28-34` | ### 1.2 依赖一致性 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | LAYER-04 | `serde_yaml = "0.9"` 已弃用 | Low | `crates/zclaw-pipeline/Cargo.toml:15` | | LAYER-05 | zclaw-saas 6 个依赖未使用 workspace 声明 | Low | `crates/zclaw-saas/Cargo.toml:44-48` | ### 1.3 中间件链 6 个中间件按优先级顺序正确执行(100-700),无遗漏。 | 优先级 | 中间件 | 状态 | |--------|--------|------| | 100 | CompactionMiddleware | 错误传播可能中断链 (MW-03) | | 150 | MemoryMiddleware | 非致命错误处理正确 | | 200 | SkillIndexMiddleware | 正常 | | 400 | GuardrailMiddleware | 正常 | | 500 | LoopGuardMiddleware | 正常 | | 700 | TokenCalibrationMiddleware | 正常 | ### 1.4 Feature Gate 安全 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | **FEAT-01** | `kernel.rs:444` `config_clone` 未定义,multi-agent 编译失败 | **Critical** | `crates/zclaw-kernel/src/kernel.rs:444` | | FEAT-04 | 无 CI 步骤验证 feature gate 编译 | Low | CI 配置 | ### 1.5 代码组织 **超过 1000 行的文件**(硬限制违规): | 文件 | 行数 | 建议 | |------|------|------| | `kernel.rs` | 1,453 | 拆分为 agent/hands/triggers/approvals/skills 子模块 | | `generation.rs` | 1,080 | 提取工具调用逻辑 | | `quiz.rs` | 1,027 | 提取评分逻辑 | | `intelligence-client.ts` | 1,471 | 按域拆分 | | `kernel-client.ts` | 1,353 | 按域拆分 | | `gateway-client.ts` | 1,227 | 按域拆分 | | `saas-client.ts` | 1,213 | 按域拆分 | --- ## 维度 2:性能与稳定性 ### 2.1 CLOSE_WAIT 修复验证 **当前状态**: 部分修复,存在关键冲突。 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | **CW-1** | 全局 15s TimeoutLayer 会中断 SSE relay 流 | **Critical** | `crates/zclaw-saas/src/main.rs:187` | | **CW-2** | 客户端断开时上游请求不取消,保持 300s | **Critical** | `crates/zclaw-saas/src/relay/service.rs:252-294` | | CW-3 | PG 连接在客户端断开后仍被延迟写入任务持有 | Medium | `crates/zclaw-saas/src/relay/service.rs:301-317` | | CW-6 | Admin 代理 30s 超时对 SSE 流不够 | Medium | `admin-v2/vite.config.ts:18-19` | ### 2.2 连接池行为 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | CP-1 | Key pool 选择每请求最多 11 次顺序 DB 查询 | High | `crates/zclaw-saas/src/relay/key_pool.rs:43-141` | | CP-3 | 无熔断器,池耗尽时级联失败 | High | `crates/zclaw-saas/src/db.rs:14` | | CP-4 | Relay handler 持有 config 读锁进行 DB 操作 | Medium | `crates/zclaw-saas/src/relay/handlers.rs:161-166` | ### 2.3 异步锁模式 | 位置 | 锁类型 | 跨 await? | 风险 | |------|--------|----------|------| | `loop_runner.rs:4` | std::sync::Mutex | 否 | Low | | `loop_guard.rs:8` | std::sync::Mutex | 否 | Low | | `memory.rs:25,33` | std::sync::Mutex | 否 | Low | | `viking_adapter.rs:114-123` | std::sync::RwLock | 可能 (async trait) | Medium | ### 2.4 热路径分析 | ID | 发现 | 风险 | |----|------|------| | CL-1 | `messages.clone()` 每次迭代复制完整消息历史 | Medium | | CL-3 | `request_body.to_string()` 在重试循环中重复克隆 | Medium | | MS-1 | SSE usage 记录无限 spawned tasks | High | | MS-2 | WebSocket 无消息大小限制 | Medium | --- ## 维度 3:安全审计 ### 3.1 机密管理 (最需改进) | ID | 发现 | 风险 | 文件 | |----|------|------|------| | **SEC-1** | `saas-config.toml` 含 DB 密码且被 Git 追踪 | **Critical** | `saas-config.toml:16` | | SEC-2 | 硬编码开发 fallback 密钥存在于 release 构建中 | High | `crates/zclaw-saas/src/config.rs:238,280` | | SEC-3 | 加密密钥无轮换机制 | Medium | `crates/zclaw-saas/src/config.rs:250-291` | | SEC-4 | API key 加密复用 TOTP 密钥 | Medium | `crates/zclaw-saas/src/config.rs:250-253` | ### 3.2 认证保护 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | **RATE-1** | 公共认证端点完全绕过速率限制 | **Critical** | `crates/zclaw-saas/src/main.rs:155-182` | | AUTH-2 | TOTP 无暴力破解保护 | High | `crates/zclaw-saas/src/auth/totp.rs:84-102` | | AUTH-3 | IP 地址提取信任 X-Forwarded-For | Medium | `crates/zclaw-saas/src/auth/mod.rs:88-104` | | AUTH-5 | Argon2 使用隐含默认参数 | Medium | `crates/zclaw-saas/src/auth/password.rs:17` | ### 3.3 SSRF 防护 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | SSRF-2 | 十六进制/八进制正则误报 | Medium | `crates/zclaw-saas/src/relay/service.rs:491` | | SSRF-3 | DNS rebinding 未缓解 | Medium | `crates/zclaw-saas/src/relay/service.rs:503-518` | ### 3.4 数据保护 | ID | 发现 | 风险 | 文件 | |----|------|------|------| | **CRYPTO-1** | Provider API 密钥在数据库中明文存储 | **Critical** | `crates/zclaw-saas/src/relay/key_pool.rs:278` | | XSS-1 | `dangerouslySetInnerHTML` 渲染未净化内容 | Medium | `desktop/src/components/PipelineResultPreview.tsx:189` | | SQL-1 | 所有查询使用参数化绑定 | Info | 全部 SQL 文件 | ### 安全态势评估 | 领域 | 评级 | 说明 | |------|------|------| | SQL 注入防御 | 优秀 | 全量参数化查询 | | 密码哈希 | 良好 | Argon2id + spawn_blocking | | JWT 实现 | 良好 | 类型区分 + 刷新轮换 + 数据库验证 | | 加密实现 | 良好 | AES-256-GCM + 随机 nonce | | SSRF 深度防御 | 良好 | 多层验证 | | 机密管理 | 差 | 硬编码 + Git 泄露 + 无轮换 | | 认证端点保护 | 差 | 公共路由无速率限制 | | API 密钥存储 | 差 | 明文存储 | --- ## 维度 4:UX/功能完整性 ### 4.1 Admin V2 健壮性 | ID | 发现 | 风险 | |----|------|------| | **UX-01** | 无 Error Boundary,渲染异常崩溃整个管理面板 | High | | UX-02 | Auth token 明文存储在 localStorage | High | | UX-03 | AuthGuard 仅检查 token 存在性,不验证有效性 | Medium | | UX-04 | Config 页面内联编辑无确认直接保存 | Medium | | UX-05 | Provider 删除操作部分页面缺少 Popconfirm | Medium | | UX-06 | 401 刷新失败时直接 `window.location.href` 重定向 | Medium | ### 4.2 Admin V2 页面评分卡 | 页面 | 加载状态 | 错误状态 | 空状态 | 破坏性确认 | 表单验证 | |------|---------|---------|--------|-----------|---------| | Dashboard | ✅ | ✅ | ✅ | N/A | N/A | | Accounts | ✅ | ✅ | ⚠️ | ✅ Popconfirm | ✅ | | AgentTemplates | ✅ | ✅ | ⚠️ | ✅ Popconfirm | ✅ | | ApiKeys | ✅ | ✅ | ⚠️ | ✅ | ✅ | | Config | ✅ | ⚠️ | ❌ | ❌ 无确认 | ✅ | | Logs | ✅ | ⚠️ | ⚠️ | N/A | N/A | | Models | ✅ | ✅ | ⚠️ | ✅ Popconfirm | ✅ | | Prompts | ✅ | ✅ | ⚠️ | ✅ | ✅ | | Providers | ✅ | ✅ | ⚠️ | ⚠️ 部分 | ✅ | | Relay | ✅ | ✅ | ⚠️ | ✅ | ✅ | | Usage | ✅ | ✅ | ❌ | N/A | N/A | ### 4.3 Desktop 应用 | ID | 发现 | 风险 | |----|------|------| | UX-07 | 41 处 console.log,含用户名泄露 | Medium | | UX-08 | WebSocket 无消息大小限制 | Medium | | UX-09 | Desktop Vite 代理无超时配置 | Medium | | UX-10 | SchedulerPanel 991 行,过于庞大 | Low | | UX-11 | Hands 依赖缺失时用户提示不够清晰 | Low | | UX-12 | GatewayStore 10 处 `any` 类型 | Low | --- ## 风险热力图 ``` 影响 → Critical High Medium Low 可能性 ↓ 高 [SEC-1, RATE-1, [CW-2, CP-1, [CW-3, MS-1, [FEAT-04, CRYPTO-1] MS-1] CL-1] SIZE-04] 中 [FEAT-01, CW-1] [SEC-2, AUTH-2, [SSRF-2, UX-04, [LK-04, UX-01] UX-06] CL-2] 低 [MW-03] [LAYER-01, [AUTH-5, SEC-4, [LAYER-05, SIZE-01] UX-07] MW-05] ``` --- ## 统一问题清单 ### P0 — 立即修复(阻塞级,共 6 项) | # | 问题 | 维度 | 文件 | 修复建议 | 工作量 | |---|------|------|------|----------|--------| | F1 | multi-agent 编译错误 | 架构 | `kernel.rs:444` | `config` clone before move | 0.5h | | F2 | saas-config.toml 含密码被 Git 追踪 | 安全 | `saas-config.toml` | `git rm --cached` + 轮换密码 | 0.5h | | F3 | 硬编码开发密钥在 release 构建中 | 安全 | `config.rs:238,280` | `#[cfg(debug_assertions)]` 门控 | 1h | | F4 | 公共认证端点无速率限制 | 安全 | `main.rs:155-182` | 添加独立限制 20RPM | 2h | | F5 | SSE 流被 15s TimeoutLayer 中断 | 性能 | `main.rs:187` | 排除 relay 路由 | 1h | | F6 | Provider API 密钥明文存储 | 安全 | `key_pool.rs:278` | 调用 encrypt_value | 1h | ### P1 — 本迭代修复(共 12 项) | # | 问题 | 维度 | 文件 | 修复建议 | 工作量 | |---|------|------|------|----------|--------| | F7 | Admin V2 无 Error Boundary | UX | `main.tsx` | 添加全局错误边界 | 2h | | F8 | 客户端断开上游不取消 | 性能 | `relay/service.rs:252` | CancellationToken 传播 | 3h | | F9 | SSE usage 记录无限 spawned tasks | 性能 | `relay/service.rs:301` | 信号量限制 + 批量写入 | 2h | | F10 | Key pool 选择 11 次顺序查询 | 性能 | `relay/key_pool.rs:43` | JOIN + 内存缓存 | 3h | | F11 | 连接池无熔断器 | 性能 | `db.rs:14` | 80% 阈值返回 503 | 2h | | F12 | Worker 重试不重新入队 | 架构 | `workers/mod.rs:179` | 重新入队 + 死信队列 | 2h | | F13 | TOTP 无暴力破解保护 | 安全 | `auth/totp.rs` | 5次失败/分钟限制 | 1h | | F14 | SSRF blocked_exact 不完整 | 安全 | `relay/service.rs:468` | 移除冗余,依赖 is_private_ip | 1h | | F15 | SQL 迁移解析器按 `;` 分割 | 架构 | `db.rs:93` | 状态机解析 | 3h | | F16 | Auth token 明文 localStorage | UX | `authStore.ts:61-68` | 加密存储或 httpOnly cookie | 3h | | F17 | async 上下文 std::sync 锁 | 性能 | `viking_adapter.rs:114` | 替换为 tokio::sync | 1h | | F18 | XSS: dangerouslySetInnerHTML | 安全 | `PipelineResultPreview.tsx:189` | sanitizeHtml | 0.5h | ### P2 — 下迭代修复(共 12 项) | # | 问题 | 维度 | 文件 | |---|------|------|------| | F19 | 非 workspace 依赖声明 | 架构 | `zclaw-saas/Cargo.toml` | | F20 | console.log 清理 (41处) | UX | `desktop/src/` 16 文件 | | F21 | clone 密度过高 (65+78) | 性能 | `kernel.rs`, `loop_runner.rs` | | F22 | panic! 用于 CORS 验证 | 架构 | `main.rs:128` | | F23 | Demo 数据单条 INSERT | 性能 | `db.rs` | | F24 | kernel.rs God-object 1453行 | 架构 | `kernel.rs` | | F25 | loop_runner 流式/非流式重复 | 架构 | `loop_runner.rs` | | F26 | TS client 4文件超1200行 | 架构 | `desktop/src/lib/` | | F27 | DNS rebinding 未缓解 | 安全 | `relay/service.rs` | | F28 | IP 头欺骗影响审计日志 | 安全 | `auth/mod.rs:88` | | F29 | Desktop 代理无超时 | 性能 | `desktop/vite.config.ts` | | F30 | Argon2 隐含默认参数 | 安全 | `auth/password.rs:17` | ### P3 — 待办(共 10 项) | # | 问题 | 维度 | 文件 | |---|------|------|------| | F31 | serde_yaml 弃用 | 架构 | `zclaw-pipeline/Cargo.toml` | | F32 | API key/TOTP 密钥分离 | 安全 | `config.rs:251` | | F33 | 密钥轮换机制 | 安全 | `config.rs:250-291` | | F34 | Token 类型强制执行 | 安全 | `auth/jwt.rs:92` | | F35 | 速率限制粒度不足 | 安全 | `middleware.rs` | | F36 | 错误消息泄露加密细节 | 安全 | `crypto.rs:23,30` | | F37 | Desktop 直连 L1/L2 crate | 架构 | `desktop/src-tauri/Cargo.toml` | | F38 | Pipeline 向上依赖 Kernel | 架构 | `zclaw-pipeline/Cargo.toml` | | F39 | Config 页面无确认保存 | UX | `Config.tsx` | | F40 | 加密错误消息泛化 | 安全 | `crypto.rs` | --- ## 整改方案时间线 ### 第 1 周:P0 修复(6 项,~6h) 1. 修复 `kernel.rs:444` 编译错误 2. `git rm --cached saas-config.toml` + 轮换密码 3. 开发密钥 `#[cfg(debug_assertions)]` 门控 4. 公共认证端点添加速率限制 5. 排除 relay 路由的 TimeoutLayer 6. `add_provider_key` 调用 `encrypt_value` ### 第 2 周:P1 修复(12 项,~23h) - Admin V2 Error Boundary + Auth token 加密 - CLOSE_WAIT 根因修复(CancellationToken + spawned tasks 限制) - 连接池优化(JOIN 查询 + 熔断器) - TOTP 暴力破解防护 - Worker 重试入队 - SQL 迁移解析器升级 ### 第 3-4 周:P2 修复(12 项,~20h) - 依赖声明统一 + console.log 清理 - kernel.rs 拆分重构 - DNS rebinding 缓解 - 性能优化(clone 减少、INSERT 批量化) ### 第 5+ 周:P3 待办(10 项,持续改进) --- ## 附录:验证方式 1. **编译验证**: `cargo check --workspace --features multi-agent` 2. **Git 追踪**: `git ls-files -- saas-config.toml` 应无输出 3. **密钥搜索**: `grep -rn "dev-only|zclaw-dev" crates/` 应仅在 `#[cfg(debug_assertions)]` 块内 4. **速率限制测试**: 对 `/api/v1/auth/login` 发送 >20 RPM 验证返回 429 5. **SSE 流测试**: relay 请求持续 >15s 验证不被 TimeoutLayer 中断 6. **TypeScript**: `npx tsc --noEmit` 无错误 7. **前端构建**: `pnpm build` 成功 8. **Admin V2**: 触发渲染错误验证 Error Boundary 捕获 --- *审计完成于 2026-03-30。全部发现源自只读静态分析,未修改任何文件。*