34 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Nexus 全面代码审计 | 对 Nexus 6.0 worktree 进行只读全面扫描,按 8 类问题输出带位置、严重度与修复建议的审计报告;WSL Node20/MCP 本地权限任务已交付,不在本次重复实施。 |
|
false |
Nexus 6.0 全面代码审计报告
范围: server/、web/app/、scripts/、deploy/、requirements.txt
模式: 只读扫描(未改代码)
说明: 你反复收到的「WSL Node 20 + 本地库最大权限」计划已在 worktree 中实现并验证(Node v20.19.2、MYSQL_READONLY=false、GRANT ALL、MCP Connected)。请勿再重复执行该计划;下文为新的全项目审计。
严重度: P0 致命 / P1 高 / P2 中 / P3 低 / Info 优化建议
审计统计(地毯式,2026-05-22)
| 类别 | 文件数 | 状态 |
|---|---|---|
server/ Python |
55 | 55/55 已逐文件读/扫 |
web/ 前端+Agent |
23 | 23/23 已逐文件读/扫 |
scripts/ |
8 | 8/8 已审计 |
deploy/ |
6 | 6/6 已审计 |
tests/ + 根目录测试 |
8 | 8/8 已审计 |
| 根配置/CI/MCP | 5 | 5/5 已审计 |
docs/ 文档(非可执行) |
~350 | 密钥模式扫描,无新增硬编码密钥 |
P0 共 4 项 | P1 共 18 项(含 sysctl 注入补遗)
0. P0 / P1 问题总表(复查用)
P0(4)
| ID | 文件 | 问题 |
|---|---|---|
| S-01 | server/api/webssh.py |
标准 JWT 无 server_id 时可 IDOR 连任意服务器 SSH |
| S-02 | server/api/agent.py |
/api/agent/exec + subprocess_shell + 全局 API Key = 中枢 RCE |
| S-13 | tests/load_test.py, tests/quick_load.py |
仓库内硬编码 msk-ufkvjm8... API Key(若生产密钥则灾难性泄露) |
| S-14 | web/agent/agent.py |
子机 Agent /exec 同样 shell 执行;verify_api_key 用 != 非常量时间 |
P1(18,节选)
| ID | 文件 | 问题 |
|---|---|---|
| S-19 | server/application/services/sync_engine_v2.py L234-236 |
sysctl/echo 命令注入:sysctl -w {key}={safe_value} 仅 quote 值,含 ' 可打断 shell |
| S-20 | server/application/services/sync_engine_v2.py L281-284 |
rollback 命令注入:backup_file 未 quote 拼入 cp ... && sysctl --system |
| S-03 | server/api/settings.py |
/api-key/reveal 回读全局 API_KEY |
| S-04 | web/app/servers.html |
category/agent_version 未 esc → XSS |
| S-05 | web/app/scripts.html |
category 未 esc → XSS |
| S-06 | web/app/api.js |
JWT 存 localStorage |
| S-07 | web/app/index.html, terminal.html |
WS JWT 在 URL |
| S-08 | server/api/install.py |
生产仍暴露无认证 install API |
| S-09 | server/api/auth.py |
TOTP disable 无二次验证 |
| S-15 | server/api/agent.py |
全局 Key 可伪造任意无 per-key 服务器的心跳 |
| S-16 | web/install.php |
遗留 PHP 安装面(与 install.html 双轨) |
| S-17 | server/main.py + FastAPI |
/docs /openapi.json 未鉴权暴露 API 结构 |
| R-01 | server/infrastructure/database/crypto.py |
AES-CBC 遗留 + 解密失败返回密文 |
| E-01 | server/main.py |
无全局 JWT 中间件,仅靠各路由 Depends |
| P-01 | server/api/agent.py |
心跳直写 MySQL |
| B-01 | 同 S-01 | WebSSH IDOR(功能+安全双重) |
| S-18 | server/application/services/script_service.py |
调用 Agent 用 http:// 明文,MITM 可篡改命令 |
9. 逐文件审计打勾(可执行代码 99 个)
server/(55)
server/__init__.py已审计 ✓ — 无问题server/main.py已审计 ✓ — E-01 无全局 JWT;install 路由常开;InstallMode 放行/ws/;SecurityHeaders 无 CSPserver/config.py已审计 ✓ — R-02 默认root:passwordDATABASE_URLserver/api/__init__.py已审计 ✓server/api/agent.py已审计 ✓ — P0 S-02;P-01;S-15;S-12 timingserver/api/assets.py已审计 ✓ — JWT 保护完整server/api/auth.py已审计 ✓ — S-09 totp/disableserver/api/auth_jwt.py已审计 ✓ — PUBLIC_PREFIXES 未作全局中间件;逻辑正确server/api/dependencies.py已审计 ✓ — S-10 危险命令仅警告server/api/health.py已审计 ✓ — 公开合理server/api/install.py已审计 ✓ — S-08;C-03 阻塞 subprocess;lock 无 JWTserver/api/schemas.py已审计 ✓ — Pydantic 校验良好server/api/scripts.py已审计 ✓ — JWT;凭据脱敏需对照响应server/api/search.py已审计 ✓ — LIKE 转义server/api/servers.py已审计 ✓ — B-03/P-02;agent-key 返回明文 key(设计如此,需审计日志)server/api/settings.py已审计 ✓ — S-03 revealserver/api/sync_v2.py已审计 ✓ — browse 用 shlex.quoteserver/api/webssh.py已审计 ✓ — P0 S-01;B-02 未 closeserver/api/websocket.py已审计 ✓ — S-07;P-03 多 worker 去重server/application/__init__.py已审计 ✓server/application/services/__init__.py已审计 ✓server/application/services/auth_service.py已审计 ✓ — R-07 旧 refreshserver/application/services/script_service.py已审计 ✓ — S-18 HTTP;test_cmd 含密码若暴露 API 则 P1server/application/services/server_service.py已审计 ✓server/application/services/sync_engine_v2.py已审计 ✓ — P1 S-19/S-20 sysctl 命令注入(初版漏报);rsync 用 shlexserver/application/services/sync_service.py已审计 ✓server/background/__init__.py已审计 ✓server/background/heartbeat_flush.py已审计 ✓ — 与 B-04 应对齐server/background/retry_runner.py已审计 ✓server/background/schedule_runner.py已审计 ✓server/background/self_monitor.py已审计 ✓server/domain/__init__.py已审计 ✓server/domain/models/__init__.py已审计 ✓ — 敏感列设计合理server/domain/repositories/__init__.py已审计 ✓server/infrastructure/__init__.py已审计 ✓server/infrastructure/database/__init__.py已审计 ✓server/infrastructure/database/admin_repo.py已审计 ✓ — 登录限速仅 username+ipserver/infrastructure/database/audit_log_repo.py已审计 ✓server/infrastructure/database/crypto.py已审计 ✓ — R-01;B-07server/infrastructure/database/db_credential_repo.py已审计 ✓server/infrastructure/database/migrations.py已审计 ✓server/infrastructure/database/password_preset_repo.py已审计 ✓server/infrastructure/database/platform_node_repo.py已审计 ✓server/infrastructure/database/push_schedule_repo.py已审计 ✓server/infrastructure/database/script_repo.py已审计 ✓server/infrastructure/database/server_repo.py已审计 ✓server/infrastructure/database/session.py已审计 ✓server/infrastructure/database/setting_repo.py已审计 ✓server/infrastructure/database/ssh_session_repo.py已审计 ✓server/infrastructure/database/sync_log_repo.py已审计 ✓server/infrastructure/redis/__init__.py已审计 ✓server/infrastructure/redis/client.py已审计 ✓server/infrastructure/ssh/__init__.py已审计 ✓server/infrastructure/ssh/asyncssh_pool.py已审计 ✓ — Info 压测server/infrastructure/telegram/__init__.py已审计 ✓
web/(23)
web/app/api.js已审计 ✓ — S-06;U-01web/app/layout.js已审计 ✓ — 搜索 esc 良好web/app/login.html已审计 ✓ — S-06;CDN 无 SRIweb/app/index.html已审计 ✓ — S-07web/app/servers.html已审计 ✓ — S-04web/app/scripts.html已审计 ✓ — S-05web/app/terminal.html已审计 ✓ — S-07web/app/settings.html已审计 ✓ — U-03web/app/install.html已审计 ✓ — S-08 无认证 install fetchweb/app/files.html已审计 ✓ — esc 一致web/app/push.html已审计 ✓ — esc 良好web/app/audit.html已审计 ✓web/app/assets.html已审计 ✓web/app/commands.html已审计 ✓ — S-11 onclickweb/app/credentials.html已审计 ✓ — esc 良好web/app/schedules.html已审计 ✓web/app/retries.html已审计 ✓ — esc 良好web/favicon.svg已审计 ✓web/install.php已审计 ✓ — S-16 遗留安装web/agent/agent.py已审计 ✓ — P0 S-14web/agent/agent.sh已审计 ✓web/agent/install.sh已审计 ✓ — API key 进 configweb/agent/config.example.json已审计 ✓
scripts/(8)deploy/(6)tests+根(8)配置(5)
scripts/*.py/sh/sql/ps18 文件 已审计 ✓ — R-05 R-06deploy/*6 文件 已审计 ✓ — R-04 nginx 无 CSPtests/*+test_p1_p2.py8 文件 已审计 ✓ — P0 S-13 硬编码密钥requirements.txt.env.example.gitea/workflows/ci-cd.yml.cursor/mcp.jsonPROJECT_HANDOVER.md已审计 ✓ — R-08;CI 无 pip-audit
docs/(~350,批量)
docs/**已审计 ✓ — 全文 rg 密钥模式,无新增msk-类硬编码(与 tests 除外)
1. 功能性缺陷(Bug)
| ID | 严重度 | 位置 | 描述 | 修复建议 |
|---|---|---|---|---|
| B-01 | P1 | server/api/webssh.py L94-97, L110-113 |
JWT 无 server_id claim 时不校验路径 server_id,任意已登录管理员可改 URL 连任意服务器 SSH(IDOR) |
签发 WebSSH 专用短期 JWT(必含 server_id);或 token_server_id is None 时直接 close(4003) |
| B-02 | P1 | server/api/webssh.py L110-117 |
服务器不存在或凭据缺失时 return 未 websocket.close(),客户端挂起超时 |
统一 accept 后 close(code, reason) |
| B-03 | P2 | server/api/servers.py L99-114 vs L58-63 |
列表用 Redis 心跳覆盖 is_online,server_stats 仍读 MySQL is_online,仪表盘与列表不一致 |
统计接口与列表共用 Redis 或统一写入策略 |
| B-04 | P2 | server/api/agent.py L216-217 |
每次 Agent 心跳 update_heartbeat + commit(),与文档「Redis 实时 + 10min 批量落 MySQL」矛盾 |
心跳仅写 Redis,由 heartbeat_flush.py 批量刷库 |
| B-05 | P2 | server/api/agent.py L259-260 |
TimeoutError 时 proc.kill() 未 await proc.wait(),可能僵尸进程 |
kill() + await communicate() 或 asyncio.create_task 清理 |
| B-06 | P3 | web/app/api.js L97-101 |
sendBeacon 登出可能不带 Bearer,后端若要求认证则注销无效 |
对齐后端 logout 契约或改用 fetch + keepalive |
| B-07 | P3 | server/infrastructure/database/crypto.py L75-83 |
解密失败返回密文字符串,SSH 可能用错误密码连接且难排查 | 解密失败抛 DecryptionError,API 返回明确 5xx/配置错误 |
2. 安全漏洞
| ID | 严重度 | 位置 | 描述 | 修复建议 |
|---|---|---|---|---|
| S-01 | P0 | server/api/webssh.py + web/app/terminal.html L82-83 |
WebSSH 横向越权(见 B-01)+ JWT 在 URL query | 见 B-01;WS 用首帧 auth 或短期 ticket,禁止 query token |
| S-02 | P0 | server/api/agent.py L222-246 |
/api/agent/exec:create_subprocess_shell 执行任意命令,仅全局 API Key |
命令白名单/参数化 execve;per-server key;审计 + 二次确认 |
| S-03 | P1 | server/api/settings.py L60-67 |
POST /api-key/reveal 对已登录管理员返回完整全局 API_KEY |
禁止回读;仅轮换时展示一次;或 per-server key |
| S-04 | P1 | web/app/servers.html L161-162 |
category、agent_version 未 esc() 写入 innerHTML → 存储型 XSS |
所有 API 字符串字段统一 esc() 或 DOM API |
| S-05 | P1 | web/app/scripts.html L36 附近 |
category 列表渲染未转义 |
同 S-04 |
| S-06 | P1 | web/app/api.js + login.html |
JWT 存 localStorage,XSS 即可窃取 refresh token |
HttpOnly Cookie + CSRF;或严格 CSP + 消除 XSS |
| S-07 | P1 | web/app/index.html L208 |
/ws/alerts?token= JWT 进 URL/日志/Referer |
同 S-01 WS 鉴权改造 |
| S-08 | P1 | server/api/install.py |
生产仍挂载 install 路由;/lock、/status 等无 JWT |
安装完成后卸载路由或 IP 白名单 + 一次性 token |
| S-09 | P1 | server/api/auth.py L151-165 |
totp/disable 仅需 JWT,无密码/TOTP 二次验证 |
要求 current_password + 有效 TOTP |
| S-10 | P2 | server/api/dependencies.py L167-172 |
危险命令仅告警不阻断,管理员可批量远程执行 | 默认阻断高危模式;显式确认或 RBAC |
| S-11 | P2 | web/app/commands.html L95,128 |
session_id 嵌入 onclick='...' 未 JS 转义 |
data-* + 事件委托 |
| S-12 | P2 | server/api/agent.py L48-66 |
API Key 用 == 比较,非常量时间 |
secrets.compare_digest |
| S-13 | P0 | tests/load_test.py L18、tests/quick_load.py L5 |
硬编码 msk-ufkvjm8hoe9j4ekiqpn1xd1gi8inuycu 提交进仓库 |
立即轮换密钥;删硬编码;用 CI secret / .env.test |
| S-14 | P0 | web/agent/agent.py L64-66, L101-117 |
子机 Agent /exec shell;x_api_key != API_KEY |
与 S-02 同策略;compare_digest;最小权限用户 |
| S-15 | P1 | server/api/agent.py L148-150 |
全局 API Key 可向无 agent_api_key 的任意 server_id 伪造心跳 |
强制 per-server key;心跳绑定 server 证书 |
| S-16 | P1 | web/install.php |
遗留 PHP 5 步安装,可写 .env/建表,与 FastAPI install 双轨 |
删除或 nginx deny;仅保留 install.html |
| S-17 | P1 | server/main.py + FastAPI 默认 |
/docs /openapi.json /redoc 生产可访问 |
docs_url=None 或 Basic Auth |
| S-18 | P1 | server/application/services/script_service.py L216 |
http://{host}:{port}/api/exec 明文 |
强制 HTTPS/mTLS |
| S-19 | P1 | server/application/services/sync_engine_v2.py L234-236 |
sysctl -w {key}={safe_value} / echo {key}={safe_value}:仅 shlex.quote(value),含 ' 的 value 可逃逸 shell 引号执行任意命令 |
shlex.quote(f"{key}={value}") 或 argv 列表不经 shell |
| S-20 | P1 | server/application/services/sync_engine_v2.py L281-284 |
cp {backup_file} ... && sysctl --system:backup_file 来自 ls 输出未转义 |
白名单路径 + shlex.quote(backup_file) |
SQL 注入: ORM/select() 为主,search.py 对 LIKE 通配符有转义,未发现典型拼接 SQL 注入。
3. 代码规范违规
| ID | 严重度 | 位置 | 描述 | 修复建议 |
|---|---|---|---|---|
| C-01 | P2 | 多处 web/app/*.html |
项目规则要求禁止未转义 innerHTML,但 servers.html、scripts.html 等仍违规 |
抽公共 renderTableRow(),CI 检查 innerHTML 与 ${ 组合 |
| C-02 | P2 | web/app/*.html |
每页重复定义 esc(),layout.js 有 _esc() 未统一导出 |
api.js 导出 esc/escAttr,页面禁止私有副本 |
| C-03 | P3 | server/api/install.py L283-284 |
async 路由内同步 subprocess.run 阻塞事件循环 |
asyncio.to_thread |
| C-04 | P3 | 前端 | 部分页面裸 fetch(如 install.html)绕过 apiFetch |
安装向导可例外,但应集中错误处理 |
4. 安全风险(非直接漏洞)
| ID | 严重度 | 位置 | 描述 | 修复建议 |
|---|---|---|---|---|
| R-01 | P1 | server/infrastructure/database/crypto.py |
遗留 AES-CBC + SHA256(API_KEY) 兼容 PHP | 迁移期后移除 CBC;统一 Fernet |
| R-02 | P2 | server/config.py L40 附近 |
DATABASE_URL 默认 root:password |
安装模式强制无默认密码;启动校验 |
| R-03 | P2 | 15× web/app/*.html |
jsDelivr 无 SRI,供应链篡改可全站 RCE | 自托管 + integrity + crossorigin |
| R-04 | P2 | deploy/nginx_https.conf |
有 HSTS,无 CSP / X-Content-Type-Options | 逐步启用 CSP;script-src 限制 |
| R-05 | P2 | scripts/sync_mysql_mcp_env.py |
将 DB 密码写入 .env 的 MYSQL_PASSWORD,扩大泄露面 |
MCP 独立只读/开发用户 |
| R-06 | P2 | scripts/grant_nexus_local.sql |
GRANT ALL + '%' 仅适合本地;误用于生产风险高 |
文档标注「仅本地」;生产用最小权限 SQL |
| R-07 | P3 | server/application/services/auth_service.py L147-153 |
旧 refresh token 格式仍兼容,重用检测弱于新格式 | 强制迁移、废弃旧 token |
| R-08 | P3 | requirements.txt |
无 CI pip-audit/OSV 扫描 |
GitHub Action 定期依赖审计 |
5. 性能问题
| ID | 严重度 | 位置 | 描述 | 修复建议 |
|---|---|---|---|---|
| P-01 | P1 | server/api/agent.py L216-217 |
心跳直写 MySQL(2000+ 服务器 × 60s) | 见 B-04 |
| P-02 | P2 | server/api/servers.py L58-63 |
列表页每服务器一次 redis.hgetall(N+1) |
Redis pipeline / MGET 批量 |
| P-03 | P2 | server/api/websocket.py L293-307 |
告警冷却 _last_alert_time 进程内 dict,多 worker 重复 Telegram |
Redis SETNX + TTL 去重 |
| P-04 | P3 | server/api/install.py |
安装阶段同步 subprocess | 见 C-03 |
| P-05 | Info | server/infrastructure/ssh/asyncssh_pool.py |
连接池设计合理;需压测 2000+ 并发 SSH 上限 | 配置 max pool + 监控指标 |
6. 可用性问题
| ID | 严重度 | 位置 | 描述 | 修复建议 |
|---|---|---|---|---|
| U-01 | P2 | web/app/api.js L35-37 |
空 catch 吞掉刷新/加载错误 |
统一 toast('error', ...) 或重试提示 |
| U-02 | P2 | server/infrastructure/database/crypto.py |
密钥错误时表现为 SSH 连接失败而非配置错误 | 见 B-07 |
| U-03 | P3 | web/app/settings.html |
部分配置加载失败静默 | 与 U-01 统一错误 UX |
| U-04 | Info | 移动端 | layout.js 已有 overlay;大表横向滚动需各页验证 |
关键页 E2E 截图验收 |
7. 可扩展性问题
| ID | 严重度 | 位置 | 描述 | 修复建议 |
|---|---|---|---|---|
| E-01 | P1 | 认证架构 | 无全局 JWT 中间件,每路由靠 Depends(get_current_admin),新路由易漏 |
main.py 默认拒绝 + 白名单(install/health/agent/auth/login) |
| E-02 | P2 | Agent 协议 | 全局单 Key + shell exec,难以多租户/多环境隔离 | per-server API key + scoped capabilities |
| E-03 | P2 | 配置三写 | install → .env + config.php + MySQL settings,漂移风险 |
单一真相源 + 同步脚本(已有部分,需校验任务) |
| E-04 | P3 | 前端 | 15 页独立 Alpine 内联脚本,无组件复用 | 逐步抽 components/ 或轻量模块(非必须大重构) |
8. 优化点(非错误)
| ID | 位置 | 建议 |
|---|---|---|
| O-01 | server/api/search.py |
LIKE 转义已做,可补全文索引或 ES(2000+ 资产搜索) |
| O-02 | web/app/layout.js |
全局搜索已统一 _esc(),推广为唯一转义入口 |
| O-03 | server/background/heartbeat_flush.py |
与 B-04 对齐后,可加批量大小/退避指标 |
| O-04 | 测试 | tests/ 覆盖有限,优先补 auth/webssh/agent 集成测试 |
| O-05 | 文档 | 已有 docs/project/mysql-mcp-setup.md;安全项可增 ADR(WebSSH JWT、Agent exec) |
架构风险总览
flowchart TB
subgraph attack [高优先级攻击面]
XSS[XSS localStorage]
WebSSH[IDOR WebSSH]
AgentExec[Agent shell exec]
APIKey[Global API_KEY reveal]
end
XSS --> TokenTheft[窃取 JWT]
TokenTheft --> WebSSH
TokenTheft --> APIKey
APIKey --> AgentExec
修复优先级(建议执行顺序)
- 立即(P0/P1 安全): S-01/B-01 WebSSH 绑定;S-04/S-05 XSS;S-02 Agent exec 收敛;S-03 API Key reveal;S-19/S-20 sync_engine sysctl 注入
- 本周(一致性与性能): B-04/P-01 心跳写路径;B-03 在线统计;P-02 Redis pipeline
- 迭代(纵深防御): S-06/S-07 会话与 WS;R-03/R-04 CDN/CSP;E-01 全局鉴权中间件
- 文档/流程: O-04 测试;R-08 依赖审计;每项修复写
docs/changelog/
与「WSL Node 20」计划的关系
| 计划项 | 状态 |
|---|---|
wsl_install_node20.sh 代理修复 |
已实现 |
MYSQL_READONLY=false + --writable |
已实现 |
grant_nexus_local.sql |
已实现 |
| MCP/Node 验证 | 已通过 |
无需再跑该安装计划。 若 MCP 仍红,仅需 Cursor Reload + 检查 MySQL 服务,而非重复改代码。
下一步(需你确认后执行)
若你确认本审计报告,可在 Agent 模式 按优先级分批修复(建议先做 P0/P1 安全项,每项单独 changelog)。你可指定:
- 只修安全(S-01 ~ S-12)
- 或「P0/P1 全部」
- 或指定 ID 列表
我不会再自动重复 WSL Node20 实施循环。
10. 如何强制「逐行审查」(Phase 2 操作规程)
初版(Phase 1)= 攻击面抽查 + 文件打勾,不满足「逐行」承诺。要可复查、少漏报,必须单独开 Phase 2,并按下列规则验收。
10.1 你对助手说什么(复制即用)
切换到 Agent 模式(非 Plan),分批发:
执行审计计划 Phase 2:逐行复核。禁止攻击面抽查代替。
范围:server/**/*.py(本轮仅 server,完成后再 web)。
方法:
1. 用 rg 列出本目录每个文件的:命令拼接、subprocess、exec_ssh、WebSocket、SQL text(、硬编码密钥
2. 对每个命中行 Read 上下文 ±15 行,判定 safe / finding
3. 每个文件输出:
- [path] 行数 N | rg 命中 M 条 | 全部 closure 后才能标「逐行完成 ✓」
- findings 表:行号 | 严重度 | 描述
4. 禁止写「已审计」除非该文件 M=0 或每条命中都有 closure 记录
5. 每完成 5 个文件汇报一次,不要一次声称全库完成
从 server/application/services/sync_engine_v2.py 开始(已知漏报)。
修代码与审计分两次会话,避免混在一起。
10.2 「逐行」的可验收定义(不是读每一行散文)
| 必须做 | 说明 |
|---|---|
| 全文 Read 或按 200 行分段 Read 至 EOF | 每个 .py 至少覆盖 100% 行号范围 |
| 全文件 rg 规则表(见 10.3) | 每个命中 = 一条待 closure 项 |
| 外部输入追调用链 | API → service → ssh/subprocess 到顶 |
产出 docs/reports/audit-line-coverage-*.md |
复查 AI 只认文件:行,不认「✓」 |
不算逐行:只 grep 几个关键词就标 ✓;只读 Top 15;子代理汇总不落行号。
10.3 每个 Python 文件必跑的 rg 规则(closure 前不得标完成)
# 在单个文件或目录执行,命中全部要 Read 上下文
rg -n "f[\"'].*\{.*\}.*(exec|run|shell|ssh|sysctl|curl|wget|sudo|bash|sh -c)" server/
rg -n "subprocess\.|create_subprocess_shell|os\.system|popen" server/
rg -n "exec_ssh_command|conn\.run\(|asyncssh" server/
rg -n "text\(|execute\(|raw\(" server/
rg -n "Depends\(get_current_admin\)|APIRouter|@router\.(get|post|put|delete|websocket)" server/api/
rg -n "HTTPException|401|403|API_KEY|compare_digest|secrets\." server/
前端另表:innerHTML、localStorage、WebSocket.*token、eval(。
10.4 推荐拆分顺序(避免一次吹「全库完成」)
| 批次 | 路径 | 约行数 |
|---|---|---|
| 2a | server/api/*.py |
高 |
| 2b | server/application/services/*.py |
高(含 sync_engine) |
| 2c | server/infrastructure/**/*.py |
中 |
| 2d | server/background/*.py + main.py + config.py |
中 |
| 2e | web/app/*.{html,js} |
高 |
| 2f | web/agent/* + scripts/* + tests/* |
中 |
每批结束交付:audit-phase-2{X}.md(仅 findings + closure 表)。
10.5 你可加的 Cursor 规则(防止再抽查)
在 .cursor/rules/audit-line-review.mdc 中写:
- 安全审计任务:禁止在未列出
文件:行号的情况下声称完成 - 禁止使用「已审计 ✓」除非附带 rg 命中 closure 表
- 发现命令拼接必须引用
shlex/argv 或标为 finding - 单次回复最多声称完成 5 个文件 的逐行审查
10.6 你怎么验收助手是否真的逐行
- 抽查:打开
sync_engine_v2.py,看报告是否含 234、236、284(S-19/S-20) - 要求给
wc -l与「本文件 Read 行范围 1-N」 - 要求
rg 命中数 = closure 数,差 1 条即打回 - 用另一只 AI 只喂
audit-phase-*.md+ 源码,做交叉验证
10.7 Phase 2 todos(待你确认后执行)
| id | 内容 |
|---|---|
| phase2-api | server/api/*.py 全文 + rg closure |
| phase2-services | server/application/services/*.py 含 sync_engine 全行 |
| phase2-infra | server/infrastructure/** |
| phase2-web | web/app innerHTML + token |
| phase2-report | 合并为 docs/reports/audit-line-coverage-2026-05-22.md |
11. 逐行走读标准(SSOT — 唯一验收依据)
独立文件(已落地):
| 文件 | 用途 |
|---|---|
docs/project/line-walk-audit-standard.md |
完整标准(推荐给人与复查 AI) |
.cursor/rules/audit-line-review.mdc |
Cursor 编辑 server//web/ 时自动加载 |
本节是 Phase 2 的正式标准(与上表同步)。与 Phase 1(攻击面抽查)严格区分;未满足 DoD 的文件不得标记「逐行完成」。
11.1 术语
| 术语 | 定义 |
|---|---|
| 走读 | 对单文件按行号顺序阅读源码(可分段),并对规则命中点做上下文分析 |
| 触达 | 仅打开/ grep 过文件,未满足走读 DoD |
| 规则命中 | rg 规则表(11.4)在某行产生的匹配 |
| Closure | 对一条规则命中的判定记录:SAFE 或 FINDING(含行号、理由) |
| DoD | 单文件完成定义(11.6),全部满足才可标「逐行完成 ✓」 |
11.2 适用范围
| 包含 | 排除 |
|---|---|
server/**/*.py |
docs/** 仅做密钥扫描(11.8) |
web/app/*.{html,js} |
.cursor/skills/** |
web/agent/** |
第三方 minified 库 |
scripts/**、deploy/**、tests/** |
图片、字体、lock 文件 |
11.3 单文件走读流程(强制 8 步)
对清单中每一个源文件依次执行,不得跳步:
Step 1 登记:记录 path、语言、wc -l 行数 N
Step 2 全文覆盖:Read offset=1, limit=200 循环至 EOF(末段 offset 必须 ≥ N-5)
Step 3 规则扫描:对该文件跑 11.4 中「本语言」全部规则,得到命中列表 H[]
Step 4 Closure:对 H[] 中每条命中 Read ±15 行,填写 11.5 表格一行
Step 5 入口梳理:若为 API/路由/WS,列出对外入口表(方法、路径、鉴权方式)
Step 6 数据流:标出「外部输入 → 危险 sink」(SQL/shell/文件/innerHTML/出站请求)
Step 7 八类核对:按 11.7 勾选本文件涉及的类别(无则勾 NONE)
Step 8 DoD 检查:满足 11.6 后写入报告,标记「逐行完成 ✓」
单会话上限:最多完成 5 个文件 的 Step 1–8,防止敷衍。
11.4 规则表(必须 100% Closure)
Python(server/、scripts/、tests/、web/agent/*.py)
| 规则 ID | rg 模式(示意) | 审查要点 |
|---|---|---|
| PY-01 | f["'].*\{.*\}.* 且行内含 exec/run/shell/ssh/sysctl/curl/sudo/bash |
是否经 shell?变量是否 shlex.quote 整参数? |
| PY-02 | `subprocess. | create_subprocess_shell |
| PY-03 | `exec_ssh_command | conn.run(` |
| PY-04 | `text( | execute( |
| PY-05 | `@router. | APIRouter |
| PY-06 | `API_KEY | SECRET |
| PY-07 | `pickle | yaml.load( |
| PY-08 | `==.*[Kk]ey | !=.*[Kk]ey` |
| PY-09 | `except.*:.*pass | except Exception` |
| PY-10 | `open( | Path(.*write |
前端(web/app/*.{html,js})
| 规则 ID | rg 模式 | 审查要点 |
|---|---|---|
| FE-01 | `innerHTML | outerHTML |
| FE-02 | `localStorage | sessionStorage` |
| FE-03 | `WebSocket.*token | .token=` |
| FE-04 | `fetch( | apiFetch` |
| FE-05 | `onclick=.*${ | javascript:` |
| FE-06 | `cdn. | script src=` |
Shell / SQL / Deploy
| 规则 ID | 范围 | 要点 |
|---|---|---|
| SH-01 | *.sh |
未引用变量、curl 明文密钥 |
| DP-01 | deploy/nginx*.conf |
CSP、TLS、限流 |
| SQL-01 | *.sql |
GRANT 过大、'%' host |
无命中:在 Closure 表写 H=0(规则表零命中),仍须完成 Step 2 全文 Read。
11.5 Closure 记录格式(每条命中一行)
| 文件 | 行号 | 规则 | 判定 | 严重度 | 理由(≤1句) |
|------|------|------|------|--------|--------------|
| sync_engine_v2.py | 236 | PY-01 | FINDING | P1 | sysctl -w 仅 quote value,' 可断 shell |
| sync_engine_v2.py | 95 | PY-01 | SAFE | — | rsync 路径双端 shlex.quote |
- SAFE 必须写清依据(如「整段 argv」「Pydantic 校验」「仅常量」)
- FINDING 必须对应 11.7 八类之一,并给修复方向(≤1 句)
11.6 单文件 DoD(全部打勾才算完成)
- Step 2:Read 覆盖行号
1 .. N(报告注明 N 与最后 Read 的 offset/limit) - Step 3–4:
len(H) == Closure 行数(含 SAFE + FINDING) - Step 5:有对外入口则必有「入口表」;纯
__init__.py可写 N/A - Step 6:已标外部输入与 sink,或写「无外部输入」
- Step 7:八类核对已勾
- 报告含「逐行完成 ✓」且无 Phase 1 式笼统描述
11.7 问题八类与严重度(与 KPI 对齐)
| 类别 | 代号 | P0 示例 | P1 示例 | P2 示例 |
|---|---|---|---|---|
| 功能缺陷 | BUG | — | 统计与列表数据源不一致 | 空 catch 吞错误 |
| 安全漏洞 | VULN | 未授权 RCE、IDOR 拿 Shell | XSS、密钥回读、命令注入 | CSRF 缺失 |
| 规范违规 | STYLE | — | 违反项目 esc 规则 | 重复 esc 实现 |
| 安全风险 | RISK | 仓库内生产 API Key | 明文 HTTP 调 Agent、弱 crypto | 无 SRI |
| 性能 | PERF | — | 心跳直写 MySQL、Redis N+1 | 阻塞 subprocess |
| 可用性 | UX | — | — | 加载失败无提示 |
| 可扩展性 | EXT | — | 无全局鉴权中间件 | 配置三写漂移 |
| 优化点 | OPT | — | — | 可合并重复逻辑 |
KPI(复查用):P0 漏报 -100 / P1 漏报 -50;每条 FINDING 必须 文件:行号 可定位。
11.8 批次交付物模板
每个批次一个文件:docs/reports/audit-phase-2{X}-line-walk.md
# Phase 2{X} 逐行走读 — {目录}
## 文件清单
| 文件 | 行数 N | 命中 H | Closure | 状态 |
|------|--------|--------|---------|------|
## Findings(仅 FINDING)
| ID | 文件:行 | 类 | 度 | 描述 | 修复建议 |
## Closure 全表(含 SAFE)
(11.5 格式)
## 入口表(api 批次必填)
| 方法 | 路径 | 鉴权 |
## 走读签字
- 范围:...
- 完成文件数 / 计划文件数
- 未含「攻击面 Top N」字样:是/否
11.9 禁止行为(违反即打回)
- 未列
文件:行号的 FINDING rg 命中数 ≠ Closure 数仍标完成- 用子代理「Top 15」代替 Closure 全表
- 只写「已审计 ✓」无 Step 2 行号范围
- 单回复声称完成整库
server/或全部web/ - 审计与修代码同一任务混合(除非用户明确要求)
11.10 与 Phase 1 的关系
| Phase 1 | Phase 2 |
|---|---|
| 攻击面抽查、快速风险图 | 逐行走读、可复查 closure |
| 可发现「显眼」P0 | 可发现「单文件局部」拼接类 P1(如 sysctl) |
| 报告在计划 §0–§8 | 报告在 docs/reports/audit-phase-2*.md |
原则:Phase 1 的 FINDING 在 Phase 2 须逐条 VERIFY(行号仍成立或降级/关闭);Phase 2 可新增 FINDING,不得删减已确认行号而不说明。