# Nexus 6.0 — 全面代码扫描审计报告 (Round 2 合并版)

**合并来源**: 本地深度扫描 + worktree独立审计  
**说明**: 两份独立审计报告去重合并，标注已修复项

---

## P0 — CRITICAL (立即修复)

### C-1: sync_service.py rsync命令 — Shell注入回归
- **文件**: `server/application/services/sync_service.py:195`
- **来源**: 本地审计 BUG-2
- **描述**: rsync命令f-string直接嵌入 `source_path`, `server.username`, `server.domain`, `target_path`，无 `shlex.quote()`。sync_engine_v2.py 已修复（C8），但 sync_service.py 遗漏。恶意用户名如 `root'; rm -rf /;#` 可执行任意命令。
- **修复**: `import shlex;` 所有动态参数 `shlex.quote()`

### C-2: agent.py exec — 命令注入无防护（RCE）
- **文件**: `server/api/agent.py:193-209`
- **来源**: 两份报告均发现 (本地 SEC-1 / worktree S-02)
- **描述**: `/api/agent/exec` 直接 `create_subprocess_shell(command)` 执行任意命令，无白名单/危险命令检测。仅全局API Key保护。Nexus被攻破后可对所有Agent执行任意命令。
- **修复**: 添加与 script_service.py 一致的危险命令检测；命令白名单；`secrets.compare_digest` 替代 `==` 比较API Key

### C-3: WebSSH 横向越权（IDOR）
- **文件**: `server/api/webssh.py:82-97`
- **来源**: worktree S-01/B-01
- **描述**: JWT无 `server_id` claim时不校验路径 `server_id`，任意已登录管理员可改URL连任意服务器SSH。`_verify_webssh_token()` 返回 `server_id` 但未与路径参数比较。
- **修复**: 签发WebSSH专用短期JWT（必含 `server_id`）；验证时比对 token_server_id == path server_id；不匹配则 `close(4003)`

---

## P1 — HIGH (本周修复)

### H-1: PUT/POST端点 setattr 无白名单 — 任意字段注入
- **文件**: `servers.py:121-123`, `settings.py:89-91`, `assets.py:52-54,109-111`, `scripts.py:69-71`, `servers.py:106`
- **来源**: 本地审计 BUG-4/5
- **描述**: 所有PUT端点 `for key, value in payload.items(): setattr(obj, key, value)`，攻击者可注入 `is_active=False`, `password_hash="..."`, `is_online=True` 等敏感字段。POST端点 `Server(**payload)` 同理。
- **修复**: 定义每端点允许字段白名单；或使用Pydantic请求模型

### H-2: settings/assets 端点 — 无JWT认证
- **文件**: `server/api/settings.py`, `server/api/assets.py`
- **来源**: 本地审计 SEC-2
- **描述**: 所有端点使用 `Depends(get_db)` 而非 `Depends(get_current_admin)`。任何人可读/改系统设置、创建/删除节点、查看SSH会话和命令日志。
- **修复**: 所有端点添加 `admin: Admin = Depends(get_current_admin)` 依赖

### H-3: agent.py proc.kill() — 僵尸进程泄漏
- **文件**: `server/api/agent.py:223`
- **来源**: 两份报告均发现 (本地 BUG-1 / worktree B-05)
- **描述**: `asyncio.TimeoutError` 分支 `proc.kill()` 后无 `await proc.wait()`，产生僵尸进程。
- **修复**: `proc.kill()` 后加 `await proc.wait()`

### H-4: refresh_token 并发重放攻击
- **文件**: `server/application/services/auth_service.py:105-127`
- **来源**: 本地审计 BUG-3
- **描述**: 并发请求使用同一refresh_token都能成功获取新token。违反rotation安全原则。
- **修复**: 数据库层面加唯一约束或应用层加锁

### H-5: N+1 Redis查询 — 2000+服务器性能瓶颈
- **文件**: `server/api/servers.py:40-65`
- **来源**: 两份报告均发现 (本地 PERF-1 / worktree P-02)
- **描述**: 每台服务器单独 `redis.hgetall()`，2000+服务器=2000+次Redis往返。
- **修复**: Redis pipeline 批量获取

### H-6: Agent心跳直写MySQL — 与文档矛盾
- **文件**: `server/api/agent.py:172`
- **来源**: worktree B-04/P-01
- **描述**: 每次心跳 `service.update_heartbeat()` + commit，与文档"Redis实时+10min批量落MySQL"矛盾。2000+服务器×60s = 高MySQL负载。
- **修复**: 心跳仅写Redis，由 `heartbeat_flush.py` 批量刷库

### H-7: API Key reveal 端点
- **文件**: `server/api/settings.py` (如存在 `/api-key/reveal`)
- **来源**: worktree S-03
- **描述**: 对已登录管理员返回完整全局API_KEY，一旦XSS即可窃取。
- **修复**: 禁止回读；仅轮换时展示一次

### H-8: TOTP disable 无二次验证
- **文件**: `server/api/auth.py:151-165`
- **来源**: worktree S-09
- **描述**: `totp/disable` 仅需JWT，无密码/TOTP二次验证。JWT被盗后攻击者可直接关闭双因素。
- **修复**: 要求 `current_password` + 有效TOTP码

### H-9: 全局无JWT中间件 — 新路由易漏认证
- **文件**: 架构层面
- **来源**: worktree E-01
- **描述**: 每路由靠 `Depends(get_current_admin)`，新路由开发易遗漏。settings/assets 已漏。
- **修复**: `main.py` 默认拒绝 + 白名单（install/health/agent/auth/login）

---

## P2 — MEDIUM (迭代修复)

### M-1: server_id 类型验证缺失
- **文件**: `server/api/agent.py:103`
- **来源**: 本地审计 BUG-6
- **修复**: `try: server_id = int(payload["server_id"]); except: raise 400`

### M-2: get_optional_admin session泄漏
- **文件**: `server/api/auth_jwt.py:128-133`
- **来源**: 本地审计 BUG-7
- **修复**: 接收Request参数，通过 `_get_request_session(request)` 获取session

### M-3: sshpass环境变量未设置
- **文件**: `server/application/services/sync_service.py:188-193`
- **来源**: 本地审计 BUG-8
- **修复**: exec_command调用时传递 `env={"SSHPASS": password}`

### M-4: X-Forwarded-For IP伪造
- **文件**: `server/api/auth.py:19-24`
- **来源**: 本地审计 SEC-3
- **修复**: 优先使用 `X-Real-IP` header（Nginx设置）；或使用 `X-Forwarded-For` 最后一个值

### M-5: known_hosts=None — SSH中间人攻击
- **文件**: `server/infrastructure/ssh/asyncssh_pool.py:145`
- **来源**: 本地审计 RISK-1
- **修复**: 实现known_hosts缓存机制

### M-6: 异常信息泄露服务器拓扑
- **文件**: `server/infrastructure/ssh/asyncssh_pool.py:164`
- **来源**: 本地审计 RISK-2
- **修复**: 日志记录完整错误，返回客户端隐藏内部地址

### M-7: TOTP brute-force 无限制
- **文件**: `server/application/services/auth_service.py:179-191`
- **来源**: 本地审计 RISK-3
- **修复**: TOTP验证添加速率限制（5次失败后锁定5分钟）

### M-8: payload: dict → Pydantic模型
- **文件**: 多处API路由
- **来源**: 本地审计 STD-1
- **修复**: 为每个端点创建Pydantic请求模型

### M-9: 在线统计与列表数据源不一致
- **文件**: `server/api/servers.py`
- **来源**: worktree B-03
- **修复**: 统计接口与列表共用Redis数据源

### M-10: login_attempts 缺少复合索引
- **文件**: `server/infrastructure/database/admin_repo.py:48-58`
- **来源**: 本地审计 PERF-3
- **修复**: 添加 `Index('idx_login_attempts_check', 'username', 'ip_address', 'success', 'attempted_at')`

### M-11: audit_logs/settings 无分页上限
- **文件**: `server/api/settings.py:23-27`
- **来源**: 本地审计 PERF-2
- **修复**: 添加limit上限保护

### M-12: install路由生产环境仍挂载
- **文件**: `server/api/install.py`
- **来源**: worktree S-08
- **修复**: 安装完成后卸载路由或IP白名单+一次性token

### M-13: API Key比较非常量时间
- **文件**: `server/api/agent.py:37`
- **来源**: worktree S-12
- **修复**: `secrets.compare_digest(x_api_key, settings.API_KEY)`

### M-14: 告警冷却多worker重复Telegram
- **文件**: `server/api/websocket.py`
- **来源**: worktree P-03
- **修复**: Redis SETNX + TTL 去重

### M-15: AES-CBC遗留兼容代码
- **文件**: `server/infrastructure/database/crypto.py:59-75`
- **来源**: worktree R-01
- **修复**: 迁移期后移除CBC；统一Fernet

---

## P3 — LOW (优化改进)

### L-1: `__import__("datetime")` 应改为正常import
- **文件**: `server/application/services/sync_service.py:168,200,212,219,228`
- **来源**: 本地审计 STD-2

### L-2: infrastructure层直接import到api层
- **文件**: `server/api/servers.py:17`, `server/api/agent.py:22-23`
- **来源**: 本地审计 STD-3

### L-3: Fernet key无rotation机制
- **文件**: `server/infrastructure/database/crypto.py:16-21`
- **来源**: 本地审计 SEC-4

### L-4: Redis overlay逻辑重复(DRY)
- **文件**: `server/api/servers.py:44-61` vs `:80-95`
- **来源**: 本地审计 OPT-2

### L-5: API响应含SSH username字段
- **文件**: `server/api/servers.py:206`
- **来源**: 本地审计 OPT-3

### L-6: 错误消息中英文混用
- **文件**: 多处
- **来源**: 本地审计 UX-1

### L-7: refresh token单设备限制
- **文件**: `server/domain/models/__init__.py:157-158`
- **来源**: 本地审计 SCALE-2

### L-8: batch_push顺序获取server
- **文件**: `server/application/services/sync_service.py:67-72`
- **来源**: 本地审计 PERF-4

### L-9: 前端esc()重复定义
- **文件**: 多处 `web/app/*.html`
- **来源**: worktree C-02

### L-10: 前端空catch吞错误
- **文件**: `web/app/api.js`
- **来源**: worktree U-01

### L-11: install.py同步subprocess阻塞事件循环
- **文件**: `server/api/install.py:283-284`
- **来源**: worktree C-03

### L-12: 前端15页独立内联脚本无组件复用
- **文件**: `web/app/*.html`
- **来源**: worktree E-04

---

## 汇总

| 严重度 | 数量 | 类别覆盖 |
|--------|------|----------|
| **P0 CRITICAL** | 3 | Shell注入回归、Agent RCE、WebSSH IDOR |
| **P1 HIGH** | 9 | setattr注入、无JWT认证、僵尸进程、token重放、N+1 Redis、心跳写库矛盾、API Key reveal、TOTP disable、全局JWT |
| **P2 MEDIUM** | 15 | 类型验证、session泄漏、sshpass、IP伪造、SSH MITM、信息泄露、TOTP brute-force、Pydantic、数据源不一致、索引缺失、分页、install路由、compare_digest、告警去重、AES遗留 |
| **P3 LOW** | 12 | import规范、架构违规、key rotation、DRY、字段脱敏、i18n、多设备、批量查询、前端esc统一、错误处理、install阻塞、前端复用 |

### 修复执行顺序

**第一批（P0 — 安全致命）**:
1. C-1: sync_service.py shlex.quote()
2. C-2: agent exec 危险命令检测 + compare_digest
3. C-3: WebSSH server_id绑定验证

**第二批（P1 — 安全+性能）**:
4. H-1: setattr白名单/Pydantic模型
5. H-2: settings/assets JWT认证
6. H-9: 全局JWT中间件
7. H-3: proc.kill() + await proc.wait()
8. H-4: refresh_token并发保护
9. H-5: Redis pipeline
10. H-6: 心跳仅写Redis
11. H-7: API Key reveal禁止
12. H-8: TOTP disable二次验证

**第三批（P2 — 纵深防御）**: M-1 ~ M-15

**第四批（P3 — 优化）**: L-1 ~ L-12
