审查日期: 2026-05-11
审查工具: Cline AI Security Auditor
项目版本: v0.1.0
| 编号 | 问题 | 状态 | 证据 | 备注 |
|---|---|---|---|---|
| F-01 | SSRF白名单 | ✅ Pass | erc-gateway/src/types.rs 实现 validate_upstream_url(),检查 ALLOWED_UPSTREAM_HOSTS |
白名单验证完整 |
| F-02 | 限流竞态 | ✅ Pass | erc-gateway/src/main.rs 使用 SQLite UPSERT 原子操作 |
INSERT ... ON CONFLICT DO UPDATE ... RETURNING |
| F-03 | Panic消除 | 仍有多处 unwrap() 存在 |
见技术债务清单 | |
| F-04 | 请求体大小限制 | ✅ Pass | erc-gateway/src/main.rs 设置 DefaultBodyLimit::max(10 * 1024 * 1024) |
10MB 限制 |
| F-05 | 上游响应验证 | ✅ Pass | erc-gateway/src/main.rs 实现响应体大小和 JSON 结构验证 |
50MB 限制 |
| F-06 | 数据库文件权限 | ✅ Pass | erc-gateway/src/main.rs 调用 set_db_permissions() |
Windows/Unix 兼容 |
| F-07 | 构建锁版本 | ✅ Pass | build.ps1 使用 --locked 标志 |
依赖版本锁定 |
| F-08 | Nonce原子递增 | ✅ Pass | erc-gateway/src/recorder.rs 使用 UPSERT |
原子递增实现 |
| F-09 | bincode固定编码 | ✅ Pass | erc-core/src/receipt.rs 使用 with_fixint_encoding().with_little_endian() |
固定编码配置 |
状态: ❌ Fail
发现的编译错误:
-
erc-core/src/receipt.rs:154-tracing模块未找到error[E0433]: cannot find module or crate `tracing` in this scope -
erc-core/src/lib.rs:63- 类型不匹配error[E0308]: mismatched types expected `&[u8]`, found `&Result<Vec<u8>, String>` -
erc-core/src/lib.rs:73- 返回类型错误error[E0308]: mismatched types expected `String`, found `Result<String, String>`
| 问题 | 风险级别 | 位置 | 描述 |
|---|---|---|---|
| 硬编码 API Key | 🔴 Critical | .env |
UPSTREAM_API_KEY=sk-cbf75ae16aa94c90b2be554f27b4b87f 已提交到仓库 |
| 硬编码测试 Token | 🟡 Medium | public/trace-viewer.html |
token=test-token-123 |
| unwrap/expect 调用 | 🟡 Medium | 多处 | 见技术债务清单 |
| 模块 | 状态 | 完整度 | 核心功能 | 备注 |
|---|---|---|---|---|
| erc-core | 90% | Receipt 结构体、Event 枚举、Ed25519 签名、Merkle 树 | 需修复编译错误 | |
| erc-gateway | ✅ 完整 | 95% | 透明代理、事件录制、限流、SSRF 防护 | 核心功能完整 |
| erc-store | ✅ 完整 | 100% | SQLite 数据库封装、原子 Nonce、Event/Receipt 查询 | 功能完整 |
| erc-query-api | ✅ 完整 | 95% | REST 端点、Token 认证、CORS 严格化 | 功能完整 |
- ✅ 请求转发到
UPSTREAM_URL - ✅ 支持多模型认证头格式(
UPSTREAM_API_KEY/ANTHROPIC_API_KEY) - ✅ 上游 URL 白名单验证
- ✅ 请求体大小限制(10MB)
- ✅ 响应体验证(50MB + JSON 结构检查)
- ✅ SQLite 连接管理
- ✅ Event 流持久化(
events表) - ✅ Receipt 持久化(
receipts表) - ✅ 原子 Nonce 分配(
nonce_counters表)
- ✅
GET /api/v1/receipts- Receipt 查询 - ✅
GET /api/v1/traces/causality- 因果链查询 - ✅
GET /api/v1/executions/events- 执行事件查询 - ✅ API Token 认证(
ERC_API_TOKEN) - ✅ CORS 严格化(
ERC_CORS_ORIGIN) - ✅ Trace Viewer 静态页面
- ✅
public/trace-viewer.html已存在 - ✅ 通过 Query API 的静态文件服务提供访问
⚠️ 硬编码测试 Token(test-token-123)
| 检查项 | 状态 | 备注 |
|---|---|---|
| docker-compose.yml 与 Dockerfile 匹配 | ✅ Pass | 服务名和端口一致 |
| Rust 基础镜像 | ✅ Pass | 使用 rust:1.82-slim |
| Cargo 国内源配置 | ✅ Pass | rsproxy.cn 镜像源 |
| Python 依赖配置 | ✅ Pass | erc-sdk-py 已配置 |
| 健康检查配置 | ✅ Pass | 两个服务都有健康检查 |
.env.example 覆盖情况:
| 变量 | 必填 | 默认值 | 状态 |
|---|---|---|---|
UPSTREAM_API_KEY |
✅ 是 | 无 | ✅ 已覆盖 |
ERC_API_TOKEN |
✅ 是 | 无 | ✅ 已覆盖 |
ALLOWED_UPSTREAM_HOSTS |
✅ 是 | 无 | ✅ 已覆盖 |
UPSTREAM_URL |
❌ 否 | https://api.deepseek.com/anthropic/v1/messages |
✅ 已覆盖 |
ERC_CORS_ORIGIN |
❌ 否 | http://localhost:3000 |
✅ 已覆盖 |
GATEWAY_LISTEN |
❌ 否 | 0.0.0.0:8080 |
✅ 已覆盖 |
| 检查项 | 状态 | 备注 |
|---|---|---|
| 端口配置(8080/8082) | ✅ 一致 | 代码和文档匹配 |
| 健康检查端点 | ✅ 一致 | /health 端点存在 |
| API 端点路径 | ✅ 一致 | /api/v1/* 路径匹配 |
| 环境变量名称 | ✅ 一致 | 变量名完全匹配 |
| 检查项 | 状态 | 备注 |
|---|---|---|
| 架构图描述 | ✅ 一致 | 四层架构(Gateway → Store → Query API → 审计) |
| 核心特性描述 | ✅ 一致 | 一行代码接入、不可篡改审计轨迹、独立可验证 |
| 快速开始步骤 | ✅ 一致 | Docker 部署流程正确 |
| 端口配置 | ✅ 一致 | 8080 (Gateway) / 8082 (Query API) |
| 功能项 | 标注状态 | 实际状态 | 一致性 |
|---|---|---|---|
| Receipt 生成与签名 | ✅ | ✅ | ✅ 一致 |
| Event 录制 | ✅ | ✅ | ✅ 一致 |
| 透明代理 | ✅ | ✅ | ✅ 一致 |
| 认证授权 | ✅ | ✅ | ✅ 一致 |
| 限流保护 | ✅ | ✅ | ✅ 一致 |
| CORS 配置 | ✅ | ✅ | ✅ 一致 |
| SSRF 防护 | ✅ | ✅ | ✅ 一致 |
| Panic 安全 | ✅ 一致(标注准确) |
所有 9 个修复项(F-01 ~ F-09)在代码中均有对应实现,文档与代码一致。
- ✅ 冻结声明存在
- ✅ 不可变规则明确(禁止删除字段、禁止修改语义、新增字段必须放入 extensions)
- ✅ 版本策略清晰
- ✅ 引用
schemas/err-v1.schema.json进行校验
- ✅ 冻结声明存在
- ✅ 6 种事件类型定义完整:
execution.startedexecution.completedllm.call.completedtool.call.completedpolicy.deniedapproval.granted
- ✅ 必填字段规范明确
- ✅
erc-core/src/receipt.rs的ExecutionReceipt结构体包含所有冻结字段 - ✅
erc-core/src/event.rs的ExecutionEvent枚举包含所有 6 种事件类型 - ✅
to_canonical_bytes()使用 bincode 固定编码,符合协议要求
| 文件 | 行号 | 调用 | 风险 |
|---|---|---|---|
erc-query-api/src/main.rs |
69 | TcpListener::bind().await.unwrap() |
服务器启动失败时 panic |
erc-query-api/src/main.rs |
70 | axum::serve().await.unwrap() |
服务器运行时 panic |
erc-gateway/src/main.rs |
67 | TcpListener::bind().await.unwrap() |
服务器启动失败时 panic |
erc-gateway/src/main.rs |
68 | axum::serve().await.unwrap() |
服务器运行时 panic |
| 文件 | 行号 | 调用 | 风险 |
|---|---|---|---|
erc-gateway/src/main.rs |
37 | .expect("无法打开限流数据库") |
数据库打开失败时 panic |
erc-gateway/src/main.rs |
44 | .expect("无法创建限流表") |
表创建失败时 panic |
erc-gateway/src/recorder.rs |
20 | .expect("无法打开SQLite数据库") |
数据库打开失败时 panic |
erc-gateway/src/recorder.rs |
38 | .expect("无法创建数据库表") |
表创建失败时 panic |
erc-store/src/lib.rs |
17 | Mutex::lock().unwrap_or_else() |
锁获取失败时 exit |
erc-query-api/src/main.rs |
55 | .parse().unwrap() |
CORS 解析失败时 panic |
| 文件 | 行号 | 调用 | 风险 |
|---|---|---|---|
erc-core/src/receipt.rs |
141 | serde_json::to_string().unwrap() |
JSON 序列化理论上不会失败 |
erc-core/src/receipt.rs |
145 | bincode::serialize().expect() |
bincode 序列化理论上不会失败 |
| 类型 | 位置 | 值 | 风险级别 | 建议 |
|---|---|---|---|---|
| API Key | .env |
sk-cbf75ae16aa94c90b2be554f27b4b87f |
🔴 Critical | 立即移除,使用环境变量注入 |
| 测试 Token | public/trace-viewer.html |
test-token-123 |
🟡 Medium | 移除或使用配置参数 |
| 默认监听地址 | erc-gateway/src/types.rs |
0.0.0.0:8080 |
🟢 Low | 已通过环境变量覆盖 |
| 默认 CORS 源 | erc-query-api/src/main.rs |
http://localhost:3000 |
🟢 Low | 已通过环境变量覆盖 |
| 功能 | 状态 | 备注 |
|---|---|---|
| 多 Agent 因果图 | ❌ 未实现 | GET /api/v1/traces/causality 端点存在但功能有限 |
| Stripe 计费集成 | ❌ 未实现 | 需要后续开发 |
| TEE 集成 | ❌ 未实现 | 规划中 |
| 审计报告导出 | ❌ 未实现 | README 中标注"规划中" |
| LangChain Adapter | ❌ 未实现 | README 中标注"规划中" |
| Token 过期/刷新机制 | ❌ 未实现 | 当前 Token 永不过期 |
| 并发限流测试 | ❌ 缺失 | 建议编写 100 并发测试用例 |
| cargo audit CI 集成 | ❌ 缺失 | 建议集成到 CI/CD |
| 问题 | 位置 | 描述 | 建议 |
|---|---|---|---|
| 编译错误 | erc-core/src/receipt.rs |
tracing 模块未在 Cargo.toml 中声明依赖 |
添加 tracing = "0.1" 到 erc-core/Cargo.toml |
| 类型不匹配 | erc-core/src/lib.rs |
sign_and_clear() 调用参数类型错误 |
使用 ? 操作符处理 Result |
| 重复的数据库连接逻辑 | erc-gateway/src/main.rs / recorder.rs |
两处都打开 SQLite 数据库 | 统一数据库连接管理 |
| 缺少错误处理 | 多处 | 网络错误直接 panic | 使用 map_err() + 优雅降级 |
当前状态:
原因:
- 编译错误:
erc-core模块存在 3 个编译错误,无法正常构建 - 安全问题:
.env文件中包含硬编码的 API Key,已提交到仓库 - Panic 风险: 仍有多处
unwrap()/expect()调用,在生产环境可能导致服务崩溃
-
修复编译错误
- 在
erc-core/Cargo.toml添加tracing = "0.1"依赖 - 修复
erc-core/src/lib.rs中的类型不匹配问题 - 确保
cargo build --release --locked成功
- 在
-
移除硬编码敏感信息
- 从
.env文件中移除真实的 API Key - 将
.env添加到.gitignore(如果尚未添加) - 使用
.env.example作为模板
- 从
-
消除关键路径的 unwrap()
erc-query-api/src/main.rs:69-70- TcpListener 绑定和服务器启动erc-gateway/src/main.rs:67-68- TcpListener 绑定和服务器启动- 使用
map_err()+process::exit(1)或返回 Result
-
移除测试用硬编码值
public/trace-viewer.html中的test-token-123
-
消除剩余的 unwrap()/expect()
- 数据库相关路径的错误处理
- CORS 解析路径的错误处理
-
完善测试覆盖
- 编写并发限流测试
- 添加集成测试
-
CI/CD 集成
- 添加
cargo audit到构建流程 - 添加自动化测试
- 添加
| 检查项 | 状态 | 阻塞级别 |
|---|---|---|
| 代码可编译 | ❌ | P0 |
| 无硬编码敏感信息 | ❌ | P0 |
| 关键路径无 panic | ❌ | P1 |
| 所有文档与代码一致 | ✅ | - |
| Docker 部署配置正确 | ✅ | - |
| 环境变量覆盖完整 | ✅ | - |
| 协议冻结声明完整 | ✅ | - |
| 安全修复无回退 | ✅ | - |
ERC Framework 在架构设计和核心功能实现方面表现良好,文档与代码一致性高,安全修复措施基本到位。然而,由于存在编译错误和硬编码敏感信息,当前版本不具备对外交付条件。
建议优先修复 P0 级别的问题(编译错误和敏感信息泄露),然后处理 P1 级别的 panic 风险。完成这些修复后,项目可以达到可交付状态。
审查完成时间: 2026-05-11 22:55 (Asia/Singapore)
审查范围: 全部 Rust 源代码、配置文件、文档、构建脚本、前端资源
审查方法: 静态代码分析、文档一致性检查、安全模式匹配