U6 檢查結果:雲端硬碟整合——八支檔案搬移處理器

U6 檢查結果:雲端硬碟整合——八支檔案搬移處理器

檢查日期 2026-09-25|對應卡片 CM-2157(母卡 CM-2152)|檢查範圍 10 個檔案 1,758 行|工具 run ID wf_6fa5dc78-d4f|驗證章 verified

§1

🔴 一句話結論

這八支背景程式拿到「任務編號、資料夾編號、檔案編號」時,一律不核對它屬於哪家客戶,而它們寫的證據表又沒有資料庫隔離,所以程式這一關確實是唯一防線,而且這道防線不存在。 我在 DEV 用客戶 131 的身分實測,把一筆證據寫進了客戶 102 的任務,也把客戶 102 的一筆證據刪掉了(實測整段回滾,沒有殘留)。

這一棒共三件:

  1. 🟠 高(runner 自行實測,未經三人面板):客戶 A 的使用者只要知道客戶 B 某個專案的編號,就能讓系統把 B 的整棵專案結構(輪次、控制項、任務名稱)建進 A 自己的雲端硬碟,之後 A 往那些資料夾丟檔,就會被當成 B 那張任務的證據匯進去。
  2. 🟡 中(工具報、三人面板 3 票全數確認):系統幫每個證據資料夾開的分享權限是「任何知道連結的人都能編輯」,連最上層的根資料夾也是。而根資料夾的編號,客戶內任何登入帳號都能從 API 拿到,不必是專案成員。
  3. 🟡 中(runner 自行實測,未經三人面板):處理 Google 變更清單、軟刪證據、對帳的程式,都用「全系統唯一」的資料夾/檔案編號去查資料,不限定客戶,所以一家客戶的背景工作可以改動另一家的證據與資料夾對應。第 1 件就是踩在這個缺口上。
§2

這一棒在檢查什麼

客戶把公司的 Google 雲端硬碟接上系統後,系統會在客戶的硬碟裡按「專案 → 輪次 → 控制群組 → 控制項 → 檢核項目 → 任務」建一整棵資料夾。之後客戶把檔案丟進任務資料夾,系統會自動抓回來存成那張任務的「證據」。這一棒的 10 支程式就是做這件事的背景工人:

檔案 行數 做什麼
app/cloud_integration/service/handlers/init_project_folders_handler.py 449 為一個專案建整棵資料夾樹
app/cloud_integration/service/handlers/process_drive_changes_handler.py 275 讀 Google 送來的變更清單,決定要匯入、軟刪還是重建資料夾
app/cloud_integration/service/handlers/import_drive_file_handler.py 264 把雲端的一個檔案抓回來,寫成證據
infra/cloud_integration/repository/drive_folder_mapping_repo_impl.py 171 「雲端資料夾 ↔︎ 系統裡的哪個東西」對應表的查詢與寫入
app/cloud_integration/service/handlers/archive_drive_file_handler.py 165 使用者在系統裡刪證據時,把雲端的檔案搬到封存資料夾
domain/cloud_integration/service/drive_folder_mapping_domain_service.py 133 對應表的業務邏輯(新增或更新、標記失聯)
app/cloud_integration/service/handlers/reconcile_task_folder_handler.py 129 任務被退回後,比對雲端與系統,補匯入或軟刪
app/cloud_integration/service/handlers/create_folder_handler.py 71 建單一資料夾
app/cloud_integration/service/handlers/rename_folder_handler.py 59 系統裡改名時同步改雲端資料夾名
app/cloud_integration/service/handlers/soft_delete_evidence_handler.py 42 雲端檔案被刪時,把對應證據標成已刪

先釐清三件事實(2026-09-25 12:40~13:05 +08 在 DEV 唯讀查證):

  • 證據表 compliance.job_evidences 沒有客戶欄位,也沒開資料庫隔離(relrowsecurity = f)。這張表要靠程式自己檢查。
  • 資料夾對應表 public.drive_folder_mappings 有開隔離,但這八支程式跑在排程的「系統身分」底下(core/scheduler.py:177 的 system_context("drive_sync_worker")),系統身分會直接繞過隔離,所以對這八支程式而言,資料庫隔離等於沒開。
  • 資料夾對應表的唯一約束是「同一家客戶內,同一個東西只能有一個資料夾」(uq_drive_folder_mappings_scope 是 (tenant_id, scope_type, scope_uid)),不同客戶可以各有一列指到同一個任務。

每支處理器拿到的編號是誰給的:

處理器 拿到的編號 從哪裡來 有沒有核對屬於這家客戶
初始化專案資料夾 專案編號 使用者打 POST /integrations/google-drive/projects/<project_uid>/init-folders,網址上填的 ❌ 沒有(見 U6-1)
處理變更清單 雲端檔案與父資料夾編號 這家客戶自己的 Google 帳號送來的變更清單 ❌ 查對應表時不限客戶(見 U6-3)
匯入檔案 任務資料夾對應編號 上一步排入的 ❌ 不核對任務屬於哪家客戶(見 U6-3)
軟刪證據 雲端檔案編號 變更清單或對帳排入的 ❌ 查證據時不限客戶(見 U6-3)
對帳 任務編號 任務退回時系統自己排入,客戶編號取自操作者 ⚠️ 上游有先核過任務,但本支不再核
封存 證據編號 使用者刪證據時系統排入 ⚠️ 上游有核過,本支用證據反查任務,不再核客戶
建資料夾/改名 任務或其他節點編號 建立、改名任務時系統排入,客戶編號取自操作者 ⚠️ 上游有核過,本支查對應表時有帶客戶編號
§3

掃到什麼(總覽)

# 這是什麼問題 出事會怎樣 要先有什麼才打得到 該補檢查的位置 嚴重度+為什麼 來源
U6-1 「初始化專案資料夾」拿網址上的專案編號就開工,不核對這個專案是不是呼叫者自家公司的 ① B 公司的專案名、輪次、控制項、任務名稱被建成資料夾,出現在 A 公司的雲端硬碟裡(外洩)。② A 往這些資料夾丟的檔,會被匯進 B 那張任務當證據(竄改稽核證據) A 公司有接雲端硬碟、有這項授權;A 的任一登入帳號知道 B 某個專案的編號(隨機長碼,猜不到,要從別處外洩) app/cloud_integration/service/drive_sync_admin_service.py:108(排入前先確認專案屬於呼叫者公司+呼叫者是專案管理者);app/cloud_integration/service/project_tree_loader.py:86(系統身分載專案時帶公司編號過濾) 🟠 高:跨公司讀+寫稽核證據,門檻只剩「知道一個專案編號」,與總表第 7 項同級 runner 開檔+DEV 分段實測(未經三人面板)
U6-2 系統建的每個資料夾(含根資料夾)都設成「任何拿到連結的人都能編輯」 拿到任一資料夾連結就能看、下載、改、刪底下全部證據,不必登入 Google 也不必登入系統;丟進任務資料夾的檔會被自動匯成正式證據 自家公司已接雲端硬碟+拿到任一資料夾連結(公司內任何登入帳號都能從系統要到根資料夾編號) infra/cloud_integration/google_drive/google_drive_api_client.py:285(改成只分享給公司網域或指定帳號);api/cloud_integration/routes/google_drive_integration_route.py:41(根資料夾編號不回給沒有讀取權限的人) 🟡 中:影響大,但這是 FR-016 設計時刻意選的做法,要決策者裁 工具 F1,面板 3:0;runner 開檔核對。與 U5-2 同一項
U6-3 背景處理器用「全系統唯一」的資料夾編號、檔案編號查資料,查詢不限定公司 一家公司的背景工作可以把證據寫進別家公司的任務、把別家的證據標成已刪、把別家的資料夾標成失聯(之後那個資料夾收到的檔都不會匯入) 這家公司自己的 Google 變更清單裡,出現一個父資料夾或檔案編號屬於別家的項目。有兩種非惡意情境會自然觸發:兩家公司接同一個 Google 帳號(系統沒擋),或踩著 U6-1 建出來的對應 infra/cloud_integration/repository/drive_folder_mapping_repo_impl.py:67、:77;infra/flow_engine/repository/job_evidence_repo_impl.py:136、:147、:155(查詢都帶公司編號,或由處理器查完核對任務所屬公司) 🟡 中:實測確認會跨公司寫與刪,但單獨觸發要靠「同一 Google 帳號接兩家」或其他缺口配合 runner 開檔+DEV 實測(未經三人面板)

現況(2026-10-01):本棒各條後來的處理結果如下(過程紀錄保留,不改)。

  • U6-1(初始化資料夾跨公司)=總表第 192 項,✅ 已修(CM-2201,commit 73f5f90af,1.21.0 出貨)。
  • U6-2(資料夾任何人可編輯)=總表第 193 項,🚫 裁定不修(決策者 10-01)。
  • U6-3(背景處理器不分公司)=總表第 194 項,✅ 已修(CM-2204,commit e00f5ed04,1.21.0 出貨)。

工具報的:一條(U6-2),三人面板 3 票全數確認。 U6-1、U6-3 是我依卡片「每支處理器問編號是誰給的」逐支追出來、再到 DEV 實測的,沒有經過三人面板投票。

§4

工具報的逐條

F1 → U6-2 🟡 每個雲端資料夾都「任何拿到連結的人都能編輯」(中,3:0)

與 U5-2 同一項。 U5 從「建資料夾」那一側報到,U6 從「建樹」與「把檔案匯成證據」這一側報到,是同一個根因。總表只登記一項。

  • 在哪:app/cloud_integration/service/handlers/init_project_folders_handler.py:448(建整棵樹時每個資料夾都呼叫);同一個呼叫也在 create_folder_handler.py:59、archive_drive_file_handler.py:157。權限內容寫死在 infra/cloud_integration/google_drive/google_drive_api_client.py:285-301:{type: anyone, role: writer, allowFileDiscovery: false}。
  • 白話說明:「anyone/writer」的意思是任何人拿到連結都能編輯。allowFileDiscovery: false 只讓它搜尋不到,不擋拿到連結的人。根資料夾 GuidantAI 也是這樣設,而子資料夾會繼承上層的分享。所以只要拿到根資料夾連結,全公司每個專案的證據都打得開。
  • 根資料夾編號怎麼拿到:GET /integrations/google-drive 只要登入加授權,不看能力點,回傳內容就有 root_folder_id(api/cloud_integration/routes/google_drive_integration_route.py:36-49、回傳格式 api/cloud_integration/serializers/google_drive_integration.py:13)。程式註解說刻意不掛能力點,理由是一般成員的頁面要判斷「有沒有連線」。但判斷有沒有連線不需要根資料夾編號。
  • U6 這一側多出來的影響:丟進任務資料夾的檔,下一輪同步會被 import_drive_file_handler.py:184-226 匯成那張任務的正式證據。既有證據的檔如果被改寫(修改時間變了),系統存的檔也會被換掉(:202-208)。匯入時雖然記下了「最後修改者信箱」(drive_last_modifying_user_email),但沒有任何地方核對這個人是不是專案成員。
  • 是設計不是漏寫:docs/features/FR-016-2604-google-drive-sync/design.md:52、:297-303 明寫「統一用 anyoneWithLink + writer」「拿到連結=拿到編輯權,請提醒管理者保管連結」。所以這條要決策者裁要不要改,不是單純修 bug。
  • 建議修法:分享改成只給公司的 Google Workspace 網域(type: domain),或只分享給專案成員的帳號;根資料夾編號從狀態查詢拿掉,或改成要有讀取權限才回;匯入前核對最後修改者是不是專案成員。
  • HIGH 級自行核對:工具評為中,不屬 HIGH。以上檔案行號我逐一開檔確認過。
§5

runner 自行追出的兩條

U6-1 🟠 知道別家公司的專案編號,就能把它的整棵結構建進自己的硬碟,再往裡面塞證據(高)

  • 在哪:
    • 入口 api/cloud_integration/routes/google_drive_sync_route.py:101-122(POST /integrations/google-drive/projects/<project_uid>/init-folders):只掛了「已登入」與「有雲端授權」,公司編號取自呼叫者,專案編號直接取網址。
    • app/cloud_integration/service/drive_sync_admin_service.py:108-131:直接排入工作,不查專案。註解寫「前端已經只讓專案管理者看到按鈕,後端不另外檢查」。
    • 背景執行 init_project_folders_handler.py:83-105 → project_tree_loader.py:86-91:用「系統身分+管理者」載專案(SYSTEM_USER_ID = 0、SYSTEM_IS_ADMIN = True),而排程本身就在系統身分底下,資料庫隔離也被繞過。
    • 寫對應表 init_project_folders_handler.py:365-407 的 _ensure_folder:以「呼叫者的公司編號+別家的任務編號」寫一列。資料庫的唯一規則是「同一家公司內不重複」(uq_drive_folder_mappings_scope),所以擋不住。
  • 白話說明:這個按鈕是「幫這個專案在雲端硬碟重建資料夾」。後端收到專案編號後,沒問「這是你們公司的專案嗎」就交給背景工人,而背景工人用的是系統最高身分,什麼都查得到。結果是把別家公司的專案結構抄進呼叫者自己的雲端硬碟。
  • 出事會怎樣:
    1. 外洩:B 公司的專案名、每一輪的名稱、控制群組與控制項、檢核項目標題、每張任務名稱,全變成 A 公司硬碟裡的資料夾名。
    2. 竄改證據:對應表裡現在有一列「A 的資料夾 → B 的任務」。A 往那個資料夾丟檔,A 自己的同步流程查到這列對應,就用任務編號去找任務(import_drive_file_handler.py:103-105)。找到的是 B 的任務,證據就寫進 B 的任務(:210-226)。B 公司的稽核人員會在自己的任務裡看到一份來源不明的證據。
  • DEV 實測(2026-09-25 12:55~13:05 +08,整段回滾):
    • 用系統身分、以客戶 131 的立場,載客戶 102 的專案 c93f3dbb-…:成功載出專案名與輪次。證實背景載入完全不分公司。
    • 用客戶 131 的身分跑匯入處理器,對應編號指向一個任務資料夾,而那個任務屬客戶 102(任務 ba6a3d00-…,內部編號 14795):證據成功寫進客戶 102 的任務 14795(類型「連結」、網址是我填的假網址)。
    • 「建對應表那一步」沒有實跑:DEV 的客戶 131 沒接雲端硬碟,而這一步必須呼叫 Google。這一步是依程式碼加資料庫唯一規則判斷的,見文末「環境打折」。
  • 要先有什麼:A 公司已接雲端硬碟、有雲端授權;A 的任一登入帳號知道 B 的某個專案編號。專案編號是隨機長碼、猜不到,要從別處取得,例如總表第 7 項那類「知道一個編號就能讀別家資料」的缺口、截圖、客服轉寄。同一家公司內,這支入口也沒檢查呼叫者是不是該專案的管理者。前端只是把按鈕藏起來,任何有授權的成員都能直接打。
  • 建議修法:在 trigger_init_project_folders 排入前,用既有的專案守門(common/authz 的專案角色軸)確認「專案屬於呼叫者公司+呼叫者是專案管理者」。ProjectTreeLoader.load 載專案時也帶上工作所屬公司的編號,查到別家就停,作為第二道。
  • HIGH 級自行核對:上列每個行號都開檔確認過;後半段(匯入寫進別家任務)有實測。沒實跑的只有「建對應表」這一步,已在上面標明。

U6-3 🟡 背景處理器用全系統唯一的編號查資料,不限定公司(中)

  • 在哪(查詢都沒帶公司編號):
    • 資料夾對應表:drive_folder_mapping_repo_impl.py:67-75 get_by_drive_folder_id、:77-83 get_by_uid;drive_folder_mapping_domain_service.py:108-119 mark_unlinked_by_drive_id。
    • 證據表:infra/flow_engine/repository/job_evidence_repo_impl.py:136-145 get_by_drive_file_id、:147-153 …_including_deleted、:155-166 soft_delete_by_uid。
  • 誰在用:
    • 處理變更清單 process_drive_changes_handler.py:164:把資料夾標成失聯。:222 認資料夾搬家。:256-262 找任務資料夾。:271-275 判斷是不是封存資料夾。
    • 匯入 import_drive_file_handler.py:91:拿對應編號,只查「是不是任務資料夾」,不查是不是這家公司的。:142:用檔案編號找既有證據。
    • 軟刪 soft_delete_evidence_handler.py:34-37:整支只有檔案編號,沒有任何公司判斷。
    • 對帳 reconcile_task_folder_handler.py:101。
  • 白話說明:Google 的資料夾、檔案編號在全世界是唯一的,程式就假設「查到誰就是誰」。但背景工作是「以某家公司的名義」在跑,查到的資料卻可能屬於另一家。程式從頭到尾沒有比對「這筆資料的公司」和「這份工作的公司」是否相同。
  • DEV 實測(同上時段,整段回滾,Google 端用假物件):
    1. 以客戶 131 的名義處理一筆變更:「一個檔案,父資料夾是客戶 102 的任務資料夾」→ 排入了一張匯入工作,帶的是客戶 102 那個任務資料夾的對應編號。
    2. 以客戶 131 的名義跑那張匯入 → 證據寫進客戶 102 的任務(同 U6-1 實測)。
    3. 以客戶 131 的名義跑軟刪,檔案編號是客戶 102 唯一一筆雲端同步證據的 → 那筆證據從有效變成已刪。
    • 事後唯讀查 DEV(13:06):假檔案編號 0 筆,客戶 102 那筆證據 is_deleted = f,確認全數回滾,沒有殘留。
  • 另外讀碼看到、沒實測的一條分支:匯入時如果用檔案編號找到的既有證據屬於別家(:142),而且修改時間不同,程式會走「更新既有證據」(:202-208)。也就是把 A 公司下載的檔掛到 B 公司的證據上,檔案本體還存在 A 公司的儲存空間。
  • 要先有什麼(為什麼評中不評高):這條的觸發點是「這家公司自己的 Google 變更清單裡,出現屬於別家的編號」。變更清單是 Google 依那個 Google 帳號看得到的檔案產生的,攻擊者不能自己亂填。會自然發生的情境有三種:
    • 兩家公司接同一個 Google 帳號:資料庫只規定「一家公司一筆授權」(tenant_drive_integrations_tenant_id_key),沒規定「一個 Google 帳號只能接一家」(DEV 已查)。顧問公司替多家客戶代管就可能這樣接。接了之後兩家的變更清單互相看得到對方的資料夾,證據會互相串來串去,不需要任何人有惡意。這是依程式碼推論,DEV 只有一家接硬碟,沒辦法實跑。
    • 踩著 U6-1:U6-1 建出了跨公司的對應列,之後就一路走這條。
    • 踩著 U6-2:A 拿到 B 的資料夾連結,用自己的 Google 帳號往 B 的資料夾放檔,這個檔就會出現在 A 的變更清單裡。這是依 Google 行為推論,沒實測。
  • 建議修法:對應表的兩支查詢加上公司編號參數,處理器一律帶工作所屬的公司編號。證據表沒有公司欄位,所以匯入、軟刪在動手前要先「由證據反查任務 → 任務所屬公司」,和工作的公司比對,不同就停。長期根治是證據表補公司欄位並開資料庫隔離(與總表第 7 項同一張表)。另外考慮在接硬碟時拒絕「這個 Google 帳號已被別家接過」。
§6

卡片點名的疑點逐條回答

① 五支處理器寫證據前,有沒有確認「這個任務屬於這家公司」?——🔴 成立(U6-1、U6-3)

處理器 結果 依據
匯入 import 🔴 不確認 對應編號進來只查類型與是否失聯(:91-101),任務用對應裡的編號直接查(:103),實測寫進別家任務
軟刪 soft_delete 🔴 不確認 整支只有檔案編號(:30-37),實測刪掉別家證據
處理變更清單 process_drive_changes 🔴 不確認 不直接寫證據,但決定要排哪張匯入/軟刪,查對應時不帶公司(:256-262),實測排出指向別家任務的匯入
對帳 reconcile 🟡 部分 找任務資料夾時有帶公司編號(:75),所以只看得到自家的對應;但如果對應本身是 U6-1 造出來的跨公司列,後面就照單全收。排出的軟刪一樣走不分公司的軟刪處理器
封存 archive ✅ 實際上擋得住 用證據反查任務後,以「工作的公司+任務」找資料夾(:105-112)。證據如果是別家的,就找不到資料夾,直接判定失敗,不會搬檔。上游 JobEvidenceService.delete_job_evidence 的權限屬另一棒範圍,本棒沒追

② 匯入檔案:檔名、大小、類型有沒有限制?——🟢 大致不成立,列兩個小觀察

  • 大小:先看 Google 回報的大小,超過上限(預設 20 MB,config/config.py:252)直接判失敗、不重試(import_drive_file_handler.py:172-182)。下載時邊下邊量,超過就停(google_drive_api_client.py:262-282)。✅ 有限制。
    • 小觀察:Google 套件每次下載一段的預設大小是 100 MB,檢查在「每段下完之後」才做。所以超過上限時,最多會先在記憶體裡放到約 100 MB 才停。同步工作最多 4 條同時跑,最壞約 400 MB。實際上大小先在前面擋過一次,要 Google 回報的大小與實際內容不符才會走到這裡,風險低,不列項。
  • 檔名:我拿 ../../etc/passwd、a./../../../tmp/pwn、含空字元等惡意檔名,實跑上傳套件的存檔路徑產生器(jedi_file_upload/common/utils/file_utils.py:10-32)。磁碟上的檔名一律是「時間+隨機碼+副檔名」。副檔名取最後一個點之後的字,不可能含 ..,所以跳不出儲存目錄。✅ 不成立。
    • 小觀察:副檔名可以含 /,會在儲存目錄底下多開一層子目錄,不會跳出去。這是上傳套件的共用行為,不是 U6 獨有,屬檔案上傳那塊。
  • 類型:沒有副檔名白名單,一律以 application/octet-stream 存。這跟一般上傳路徑一樣,而且系統本來就要收各種證據檔,不列項。Google 文件類只存連結、不下載內容。

③ 變更清單裡的檔案編號如果指到別家公司的資料夾,會不會照單全收?——🔴 成立(U6-3)

會。_find_task_mapping_for_file(process_drive_changes_handler.py:256-262)拿父資料夾編號查對應表,不帶公司,查到任務資料夾就排匯入。我已在 DEV 實測排出這張工作。移除事件更直接:只要檔案編號就排軟刪,同時把同編號的資料夾標成失聯(:155-165),兩件都不分公司。

④ 09-17 新增的兩個證據查詢,有沒有限定任務範圍?——✅ 有,不成立

  • get_active_by_job_and_file(job_execution_id, file_id)(job_evidence_repo_impl.py:168-178):以「任務+檔案」查。
  • find_active_by_content_hash(job_execution_ids, content_hash)(:180-195):只在傳進來的任務清單裡查。

兩支都限定了任務範圍。不限定公司,公司範圍靠呼叫端 core/plugins/evidence_classification.py:429、:470 保證:後者的任務清單來自 resolve_jobs(round_id),只取這一輪的任務。呼叫端已在 FR-115 W7 掃過,本棒只確認查詢本身沒問題。

⑤「有人守了一半」共通疑點

疑點樣式 本棒結果
只驗「你是誰」沒驗「這筆是不是你的」 🔴 成立 → U6-1:入口只驗登入+授權,不驗專案歸屬
列表有守、單筆沒守 不適用:背景處理器沒有列表/單筆之分
守門寫在前端或上一層,後端繞得過 🔴 成立 → U6-1:程式註解明寫「前端已限制按鈕,後端不另外檢查」
守門條件用 or 串、其中一個恆真 ❌ 不成立
「查不到」與「沒權限」混成同一回應 不適用:背景工作沒有回應給使用者
系統身分執行時假設呼叫者是自己人 🔴 成立 → U6-1、U6-3:排程在系統身分下跑,資料庫隔離全失效,而程式假設「排進來的工作一定是這家公司自己的東西」
防重放/計次只在單一進程有效 ❌ 不成立:重複匯入靠資料庫唯一規則擋
註解寫「這裡刻意不檢查」但上一層沒檢查 🔴 成立 → U6-1(drive_sync_admin_service.py:119-122)
§7

可信度(分兩層)

層 內容 可信到什麼程度
工具正式清單 U6-2 一條 研究員提出後,三位驗證者從「打不打得到」「影響多大」「有沒有防線」三個角度各自開檔,3 票全數確認,驗證章 verified。我另外逐一開檔核對行號
runner 自行追查 U6-1、U6-3 未經三人面板投票。 每條都有開檔核對,核心結論有 DEV 實測:跨公司寫入證據、跨公司刪除證據、系統身分載別家專案、變更清單指向別家資料夾,四項都實跑成立。沒實跑的部分已逐一標出,見下方「環境打折」

為什麼工具沒報 U6-1、U6-3:工具這一棒是 low 等級,只有一位研究員讀全部範圍。U6-1 的缺口在範圍外的入口與服務(路由、drive_sync_admin_service.py、project_tree_loader.py),範圍內的處理器只是忠實執行。U6-3 要把「系統身分會繞過隔離」「證據表沒有公司欄位」「查詢不帶公司」三件事串起來才看得出來。這正是卡片要求逐支追「編號是誰給的」的原因。

§8

環境打折(一定要看)

  • 沒有兩家公司都接雲端硬碟的環境:DEV 只有客戶 102 接了雲端硬碟,客戶 131 沒接。所以實測是直接呼叫處理器、Google 端用假物件,跳過了「這家公司有沒有接硬碟」與真正的 Google 呼叫。證明的是「我方程式與資料庫不會擋」,沒有證明 Google 端的行為(例如 U6-3 情境三「A 用自己帳號往 B 的資料夾放檔,會出現在 A 的變更清單」是推論)。
  • U6-1 的完整鏈沒有一次跑完:「入口 → 載別家專案 → 建跨公司對應 → 丟檔 → 匯入寫進別家任務」五步中,第 2、5 步實跑成立。第 3 步「建跨公司對應」依程式碼與資料庫唯一規則判斷,沒實寫,因為要呼叫 Google 建資料夾。第 4 步由 U6-3 的實測 1 間接證明。
  • 應用程式目前在 DEV 開不起來:用正式的啟動流程組裝時失敗。錯誤是 FlowControlJobRepoImpl 缺 resolve_project_id_for_job,這個抽象方法定義在目前虛擬環境指向的 jedi-task-platform(jedi-wt-fix-security 工作樹),主專案還沒補實作。我改成直接組裝處理器需要的零件來實測,處理器本身的程式一行沒動。這件事跟本棒無關,但會讓本機 BE 起不來,請首腦轉給修正線。
  • 所有實測都包在同一個資料庫交易裡,最後故意中止讓它整段回滾,事後唯讀查證無殘留。實測腳本放在個人暫存目錄,不進版控。
§9

執行概況

項目 值
工具 run ID wf_6fa5dc78-d4f
報告目錄 CLAUDE-SECURITY-20260925-042332/(不進版控)
驗證章 CLAUDE-SECURITY-REVISION-fe7c471f3d7c-dirty.json,verification.status: verified
掃描版本 fe7c471f3(工作區有平行線未 commit 的改動所以標 dirty;本棒 10 支範圍檔在掃描當下沒有未 commit 改動)
範圍 10 檔/1,758 行,--effort low,focus attack-surface
研究員 派 2(一位讀全部範圍、一位專找寫死的密碼金鑰),回 2,failed 0
候選 → 面板 1 候選 → 3 票全數確認,最終嚴重度中(未被調降)
耗時/用量 約 25 分鐘;子代理約 37 萬 token
runner 自行追查 全部 10 支逐支通讀;越界讀了路由、drive_sync_admin_service.py、drive_sync_orchestration_service.py、project_tree_loader.py、drive_sync_worker.py、排程、上傳套件、job_evidence_repo_impl.py(只讀不報的接縫)
DEV 查證 唯讀查詢於 12:40~13:06 +08;實測於 12:55~13:05 +08,整段回滾

沿革見 FR-120-LOG 與 git log。