11 KiB
Phase2 P2 合并卷
生成日期: 2026-06-04 · 源文件 9 篇 · 原文
docs/archive/audits/2026-06-04-phase2/
批次索引
audit-phase2-2026-06-04-waveP2-1.md
Phase 2 深审 — Wave P2-1(Files / SSH 基础设施)
登记
入口表
Closure 表
len(H)=17, Closure=17
FINDING
无 P0/P1 新 FINDING。
L3 门控(同日记录)
DoD
- len(H) == Closure
验证
audit-phase2-2026-06-04-waveP2-2.md
Phase 2 深审 — Wave P2-2(sync_v2 全文 + 路径/Shell 依赖)
登记
入口表(sync_v2 全 22 路由)
Closure 表
len(H)=20, Closure=20
FINDING
无 P0/P1 新 FINDING。
DoD
- len(H) == Closure
验证
audit-phase2-2026-06-04-waveP2-3.md
Phase 2 深审 — Wave P2-3(WebSocket / Dashboard 告警链)
登记
入口表
Closure 表
len(H)=16, Closure=16
FINDING
无 P0/P1 新 FINDING。
DoD
- len(H) == Closure
验证
audit-phase2-2026-06-04-waveP2-4.md
Phase 2 深审 — Wave P2-4(servers.py 全文)
登记
入口表(servers.py 26 路由)
Closure 表
len(H)=20, Closure=20
FINDING
无 P0/P1 新 FINDING。
DoD
- len(H) == Closure
验证
audit-phase2-2026-06-04-waveP2-5.md
Phase 2 深审 — Wave P2-5(webssh.py 全文)
登记
入口表
Closure 表
len(H)=17, Closure=17
FINDING
无 P0/P1 新 FINDING。
DoD
- len(H) == Closure
验证
audit-phase2-2026-06-04-waveP2-6.md
Phase 2 深审 — Wave P2-6(sync_engine_v2.py 全文)
登记
入口表(服务层,经 sync_v2 API 调用)
Closure 表
len(H)=17, Closure=17
FINDING
无 P0/P1 新 FINDING。
DoD
- len(H) == Closure
验证
audit-phase2-2026-06-04-waveP2-7.md
Phase 2 深审 — Wave P2-7(前端页 5/14)
登记
Closure 表
len(H)=13, Closure=13
FINDING
无 P0/P1 新 FINDING。
DoD
audit-phase2-2026-06-04-waveP2-8.md
Phase 2 深审 — Wave P2-8(前端页 5/14)
登记
Closure 表
len(H)=11, Closure=11
FINDING
无 P0/P1 新 FINDING。
audit-phase2-2026-06-04-waveP2-9.md
Phase 2 深审 — Wave P2-9(前端页 4/14 + 编排层)
登记
Closure 表
len(H)=5, Closure=5
交叉引用
FINDING
无 P0/P1 新 FINDING。
Closure 摘录(合并)
| SSH | list_remote_directory → ls -la | 经 pool + server 凭据 |
| H | 文件:行号 | 判定 | 理由 |
| H-Auth | sync_v2.py:74–1614 | SAFE | 22 路由均 Depends(get_current_admin) |
| H-Shell | sync_v2.py:156-168 | RISK | rm -rf 删目录;JWT+审计+前端 confirm |
| H-Shell | sync_v2.py:156,165,168,223-227 | SAFE | path shlex.quote |
| H-Path | sync_v2.py:149-165 | SAFE | normalize_remote_abs_path |
| H-Clipboard | sync_v2.py:207-208 | SAFE | assert_clipboard_transfer_safe |
| H-Sandbox | sync_v2.py:302,341,413,721 | SAFE | ensure_under_nexus_upload |
| H-Source | sync_v2.py:548,1096 | SAFE | FORBIDDEN prefixes + resolve |
| H-Audit | sync_v2.py:461-475 | SAFE | 失败 log warning+exc_info,非静默 pass |
| H-Upload | sync_v2.py:876-877,977-978 | SAFE | 100MB / 500MB 上限 |
| H-ZipSlip | sync_v2.py:1000-1005 | SAFE | assert_zip + is_path_under_prefix |
| H-Download | sync_v2.py:1244-1272 | SAFE | 100MB + filename sanitize |
| H-Read | sync_v2.py:1322-1326 | SAFE | max_size 来自 payload |
| H-Write | sync_v2.py:1394-1414 | SAFE | 5MB + etag 409 冲突 |
| H-Chmod | sync_v2.py:1507-1514 | SAFE | recursive policy + test -d |
| H-Verify | sync_v2.py:1145-1146 | SAFE | sha256sum 路径 shlex.quote |
| H-Path | posix_paths.py:46-59 | SAFE | 禁 .. 与反斜杠 |
| H-Path | posix_paths.py:117-136 | SAFE | upload 前缀 + zip-slip |
| H-Sudo | remote_shell.py:35-53 | SAFE | bash -c + shlex.quote(command) |
| H-Clipboard | remote_path_validation.py:24-33 | SAFE | dest 非源子树 |
| H-Parse | unix_ls.py:70-71 | SAFE | 跳过 . .. |
| H-WS-Auth | websocket.py:304-311,340-347 | SAFE | 无 token → 4001;无效 → 4401 |
| H-WS-Token | websocket.py:366-410 | SAFE | tv/updated_at 与 HTTP JWT 一致 |
| H-WS-ADR011 | websocket.py:9,296 | RISK | query JWT;单人运维已接受 |
| H-WS-Limit | websocket.py:49-52 | SAFE | MAX_CONNECTIONS=500 |
| H-WS-Heartbeat | websocket.py:139-165 | SAFE | 30s ping / 60s zombie |
| H-WS-Channel | websocket.py:246-249,531-551 | SAFE | alerts 与 sync 分 channel/manager |
| H-WS-Dedup | websocket.py:416-437 | SAFE | Telegram 5min 冷却;WS 仍实时 |
| H-WS-Recovery | websocket.py:512-513 | SAFE | recovery 清 cooldown |
| H-Frontend-Token | useWebSocket.ts:61 | RISK | URL query token;同 ADR-011 |
| H-Frontend-Auth | useWebSocket.ts:114-116 | SAFE | 4001/4401 → forceLogout |
| H-Frontend-XSS | useWebSocket.ts:99-102 | SAFE | snackbar 文本插值,无 v-html |
| H-Frontend-Singleton | useWebSocket.ts:17-18 | SAFE | 模块级单例;App 统一 connect |
| H-Dashboard-Refresh | DashboardPage.vue:393-397 | SAFE | WS alert → reload stats/alerts |
| H-Dashboard-API | DashboardPage.vue:302-337 | SAFE | http JWT 拉 stats/alert-history |
| H-App-Lifecycle | App.vue:257-259 | SAFE | login connect / logout disconnect |
| H-Alert-API | settings.py:768-828 | SAFE | alert-history JWT + 参数化 filter |
| H-Auth | servers.py:26×路由 | SAFE | 26 端点均 get_current_admin |
| H-Mask | servers.py:1692-1698 | SAFE | password_set / agent key 前缀截断 |
| H-Encrypt | servers.py:1096-1099,559-562 | SAFE | Fernet encrypt 入库 |
| H-Allowlist | servers.py:1163-1187 | SAFE | UPDATE 字段白名单;agent_api_key 排除 |
| H-Reauth | servers.py:1256-1260,1479-1483 | SAFE | agent-key/install-cmd 需当前密码 |
| H-Reveal | servers.py:1492-1502 | SAFE | install-cmd 不用全局 API_KEY |
| H-AgentKey | servers.py:1282-1288 | SAFE | 生成后 display_once 响应 |
| H-Fallback | servers.py:626,1321 | RISK | batch/single install 可回退 settings.API_KEY |
| H-Shell | servers.py:631-633,1330-1332 | SAFE | install shlex.quote url/key/port |
| H-Sudo | servers.py:36-60 | RISK | 临时 sudoers 白名单;运维必要 |
| H-SudoPwd | servers.py:1025-1027 | SAFE | sudo -S 密码走 stdin 非 argv |
| H-CSV | servers.py:376-388,445-446 | SAFE | formula injection 防御 + 1MB 上限 |
| H-CSV | servers.py:499-501 | SAFE | MAX_IMPORT_ROWS=500 |
| H-Batch | servers.py:615,686,772,850 | SAFE | Semaphore(5) 并发上限 |
| H-Redis | servers.py:179-201,873-877 | SAFE | 心跳 overlay;失败 log warning |
| H-Audit | servers.py: CUD/batch | SAFE | 写操作 AuditLog |
| H-Crypto | crypto.py:20-26 | SAFE | 无 ENCRYPTION_KEY 则 RuntimeError |
| H-Crypto | crypto.py:52-54 | SAFE | decrypt 失败 raise,非静默 |
| H-Capability | files_capability.py:31-39 | SAFE | 只读 probe,无密码回传 |
| H-Elevation | files_elevation.py:48-55 | SAFE | apply_files_elevation_payload |
| H-Purpose | webssh.py:48-49 | SAFE | 拒绝非 webssh purpose |
| H-Bind | webssh.py:106-109 | SAFE | token server_id 须匹配路径 |
| H-TV | webssh.py:66-76 | SAFE | tv 校验;legacy updated_at +5s grace |
| H-Close | webssh.py:97-104 | SAFE | 缺 token→4001;无效→4401 |
| H-Issue | auth.py:334-346 | SAFE | 签发前 JWT + server/domain 校验 |
| H-Scope | auth_service.py:455-470 | SAFE | JWT 含 server_id + purpose + tv |
| H-Expire | auth_service.py:467 | SAFE | 15 分钟短期令牌 |
| H-WSQuery | webssh.py:88, useTerminalSessions:293 | RISK | ADR-011 query token(已接受) |
| H-Cred | webssh.py:126-135 | SAFE | key/password 配置检查 |
| H-Audit | webssh.py:137-146,353-366 | SAFE | connect/disconnect 审计 |
| H-Session | webssh.py:148-157,369-376 | SAFE | SshSession 创建/关闭 |
| H-DB | webssh.py:111-158 | SAFE | 长连接前关闭 DB session |
| H-Pool | webssh.py:167,337 | SAFE | acquire/release + stale retry |
| H-CmdLog | webssh.py:277-290,379-398 | SAFE | Enter 触发;2000 字符截断 |
| H-Danger | dependencies.py:167-180 | RISK | 危险命令仅 WARN 不阻断(设计) |
| H-Resize | webssh.py:293-296 | SAFE | cols/rows 边界默认 80×24 |
| H-Error | webssh.py:171,204 | SAFE | SSH 失败不向客户端泄露栈 |
| H-Source | sync_engine_v2.py:72-76,327-330 | SAFE | _nexus_source_path 拒绝系统路径 |
| H-Conc | sync_engine_v2.py:38,79-80 | SAFE | MAX_CONCURRENT=10 + min 入参 |
| H-DBLock | sync_engine_v2.py:89,149,190 | SAFE | _db_lock 串行写 sync_log/retry |
| H-Cancel | sync_engine_v2.py:96-136 | SAFE | Redis cancel flag;失败则继续 push |
| H-Retry | sync_engine_v2.py:193-224 | SAFE | 失败自动 pending retry;去重 |
| H-Subproc | sync_engine_v2.py:468-473 | SAFE | create_subprocess_exec 参数化 |
| H-Shlex | sync_engine_v2.py:456-458 | SAFE | key path shlex.quote |
| H-KeyTmp | sync_engine_v2.py:449-455,491-495 | SAFE | 0600 临时 key + finally unlink |
| H-Pass | sync_engine_v2.py:440-446 | RISK | sshpass -e;/proc 可见(内网运维可接受) |
| H-Remote | sync_engine_v2.py:414 | SAFE | normalize_remote_abs_path |
| H-Timeout | sync_engine_v2.py:476-482 | SAFE | RSYNC_TIMEOUT+30 kill |
| H-Output | sync_engine_v2.py:486-487 | SAFE | stdout/stderr 截断 10KB |
| H-Staging | sync_engine_v2.py:498-516 | SAFE | 仅 manual 全成功才 rmtree staging |
| H-Preview | sync_engine_v2.py:364-365 | SAFE | verbose 文件列表上限 200 |
| H-Audit | sync_engine_v2.py:267-271,380-391 | SAFE | sync_files 审计;失败 log error |
| H-TG | sync_engine_v2.py:274-291 | SAFE | Telegram 失败不阻断 |
| H-Gather | sync_engine_v2.py:254-265 | SAFE | gather 异常计入 failed |
| H-JWT | 各页 http.* | SAFE | 经 @/api JWT 客户端 |
| H-WS | DashboardPage:393-397 | RISK | useWebSocket query token(已接受) |
| H-Nav | DashboardPage:383-387 | SAFE | server_id 数字 query 路由 |
| H-Err | DashboardPage:268-345 | SAFE | load 失败 snackbar |
| H-CSV | ServersPage:391-435 | SAFE | import FormData;export 无密码列 |
| H-Batch | ServersPage:325-388 | SAFE | batch 端点 JWT;confirm 删除 |
| H-Form | ServersPage:162-176 | SAFE | 凭据经 ServerFormDialog composable |
| H-Filter | AlertsPage:150-162 | SAFE | 只读分页 API |
| H-Audit | AuditPage:126-141 | SAFE | 只读;normalizeAuditList |
| H-TG | SettingsPage:272-275 | SAFE | GET 不返 token 明文;value_set |
| H-Reveal | SettingsPage:434-460 | SAFE | API Key/TG reveal 需 current_password |
| H-Pw | SettingsPage:339-359 | SAFE | 改密 POST;表单 type=password |
| H-TOTP | SettingsPage:362-404 | SAFE | setup/enable/disable 走 auth API |
| H-CredList | CredentialsPage:253-255 | SAFE | GET 列表无密码明文 |
| H-CredPost | CredentialsPage:323-327 | SAFE | encrypted_pw 仅 POST/PUT |
| H-CredEdit | CredentialsPage:306,340,357 | SAFE | 编辑留空不修改 |
| H-SSH | CredentialsPage:346-347 | SAFE | 私钥仅提交时传输 |
| H-Cron | SchedulesPage:177 | SAFE | cron 正则校验 |
| H-Sched | SchedulesPage:173-180 | SAFE | 路径/服务器必填 |
| H-Retry | RetriesPage:146 | SAFE | retry POST JWT |
| H-CmdView | CommandsPage:139-153 | SAFE | 只读 command-logs/sessions |
| H-ScriptExec | ScriptsPage:415-419,463-467 | SAFE | exec 走后端 JWT |
| H-Quick | ScriptsPage:459-467 | RISK | 临时命令;后端 check_dangerous |
| H-Poll | ScriptsPage:527-528 | SAFE | onUnmounted stopPolling |
| H-FilesShell | FilesPage.vue:33-37 | SAFE | 逻辑在 useFilesPage(D5) |
| H-PushShell | PushPage.vue:105 | SAFE | usePushPage(D4) |
| H-TermShell | TerminalPage.vue | SAFE | useTerminalSessions(D5) |
| H-Login | LoginPage.vue | SAFE | auth.login 内存 token(D6) |
| H-NoStore | 四页 | SAFE | 无 localStorage 存密码 |