Files
Agent-System/.doc/audit/2026-09-13-document-revision-duty-etag-overwrite.md
T
WeiCHEN 4baa1220ee docs(ops): close docrev UI audits after main+post-restart PASS
Record real Playwright ledgers, mark 20 audits and 9 remediations done, and leave management-implementation-plan as plan-only.
2026-09-23 04:00:49 +08:00

3.7 KiB
Raw Blame History

title, status, created, updated, severity
title status created updated severity
文档职责伪造与保存时重取 ETag 可覆盖并发正文 done 2026-09-13 2026-09-22 critical

文档职责伪造与保存时重取 ETag 可覆盖并发正文

W3 UI-rerun 关闭(2026-09-22):status=done。真实 Playwright 账本 PASS:ui-acceptance-results.json(main UI-00..16)+ ui-acceptance-results-post-restart.json(UI-15)。任务 tip 已合入本地 dev;详见 short-term 与 测试报告。

现象

静态审查与 E2E UI-13 路径暴露两类产品缺陷:

  1. 职责提升:审核人 B 或项目外陌生人打开受控文档后,工作台把其当成编制人,出现正文编辑 / 送审动作。
  2. 并发覆盖:两窗口同开同一修订时,后保存方在点击保存瞬间重新 GET 最新 ETag,If-Match 对准已更新账本,409 不会出现,先保存方的正文被静默覆盖。

根因分析

层 问题 风险
API ListWorkflowDocumentsByProject / GET projects/{id}/documents 的 summary 不投影 document_records 的 author/reviewer/approver id+name 前端无权威职责,只能猜
前端 merge mergeWorkflowDocumentsFromServer 用当前登录用户名伪造 author,审核/批准写死「李主管」「王总监」 B 登录后 author===自己,权限矩阵显示编制人
角色解析 currentDocRole 比 name,失败默认 'author' 未知身份 fail-open,陌生人获得编辑/送审
保存 handleSaveBlockEdit 在 PATCH 前 getRevisionState 取最新 ETag 打开时基线被丢弃;后写覆盖先写
E2E UI-13b 在 A1 完整保存后才打开 A2 编辑器 不是真实竞争,无法钉住上述 ETag 缺陷

独立审查补强(同一分支):

层 问题 风险
PATCH resolvePatchEtag 在 controlled 缺基线时仍返回 0:0 服务异常被当成合法 bootstrap,可能覆盖已有账本
hydrate revision-state 5xx/网络失败只写 undefined 仍返回可编辑 AST 用户能改正文,保存再 PATCH 0:0
批注 viewer 被 cast 为 reviewer/approver,canAnnotate 对 viewer 开放 查阅者可新增评审批注
职责 isLegacyLocalDoc = !ids:服务端 duty id 为 0 仍走 name fallback 同名用户被提权为编制人

安全含义:职责伪造是越权写(viewer/reviewer 可改受控正文并送审)。ETag 刷新或 0:0 误用是完整性破坏。viewer 批注是越权写元数据。

严重度

critical

关联整改

证据

  • 代码(修复前):internal/docgov/project_docs.go summary 无职责列;web/src/lib/deliverableSync.ts author: fallbackUser.name;web/src/App.tsx 默认 'author' 与保存前 getRevisionState
  • 单测钉住:B/陌生人不成 author;stale hydrate ETag 用于 PATCH
  • 补强单测:controlled 缺 ETag/5xx 不可保存或不可打开;freeform 可 0:0;viewer 不能批注;服务端 duty id=0 不按 name 提权
  • 本轮不跑真实 E2E、不提交 evidence assets

开放问题

  • 占槽后真实 UI-13a/13b 重跑;CURRENT 仍 in_progress,不得标 done