本卡屬 FR-086(母卡 CM-XXXX,建完補號),第 2 棒:主專案的宿主接線(BE repo,scanRoot 與另兩棒不同)。只掃不修。 建議在 B1 驗收完之後跑。
掃主專案裡「接上檔案套件」的那 10 個檔(910 行)。套件本身只提供機制,真正的決策全在這半邊:這個檔案要存到哪個儲存後端、用誰的憑證去存、這個檔算不算你的。要找的是:會不會拿到別的客戶的儲存憑證、會不會取到別的客戶的檔案、憑證怎麼存怎麼傳。只找問題、不修問題。
檔數少但密度最高——這是 FR-079(jedi-bulletin)與 FR-081(jedi-issue)兩次換來的教訓:套件把安全決策外包給宿主時,十個重點有八個落在宿主側。本棒 910 行裡有一支 362 行的服務專門解析「每個租戶的儲存設定」,那正是憑證與歸屬判斷的交會點。
首腦與偵察 agent 讀過程式碼後的起點,未經驗證。工具不會照這份清單走,工具沒答的你要自己開檔查,並標明「(工具未報,人工查證)」。
app/upload_file/service/managed_file_upload_service.py:173-220 的 _adapter_for_uid——首腦盤點看到它依檔案自身記錄的 scope/type 去挑 adapter,過程中似乎沒有比對「這個檔案屬不屬於當前這個租戶/使用者」。要追:(a) 它拿到 uid 之後查出 entity,有沒有任何一步驗歸屬?(b) 若沒有,配合 B1 的②③(任意 uid 可換憑證、資料層無範圍條件),是不是就構成一條完整的跨租戶取檔路徑?這一項要與 B1 的結論合看。:46 附近首腦看到「找不到本租戶設定時借用別處憑證」的形狀。要追:借的是誰的?在什麼條件下借?借到之後存取的是哪個租戶的儲存空間?這可能是設計(共用儲存)也可能是洞,要讀 docstring 判斷意圖,再判斷意圖本身合不合理。:99-119:access_key/secret_key 從 system_config 的 JSONB 讀出,而 secure=v.get('secure', False)——預設不加密連線。要追:(a) 那些憑證在資料庫裡是明文還是加密存?(b) 讀它的路徑有沒有權限檢查?(c) secure 預設 False 意味著「沒設定就走明文」,實際部署有沒有設?(d) 憑證會不會被寫進 log 或錯誤訊息?infra/upload_file/system_storage_config_reader.py:21-57 有三支刻意用超級權限讀設定的函式。要追:為什麼需要繞過?繞過的範圍有沒有收斂到「只讀儲存設定」?有沒有可能被誘導去讀別的東西?(對照 FR-085 C1 的 CM-1559:無身分時整個隔離會關掉,這裡是刻意繞過,兩者是不同的形狀,但都要問「繞過之後範圍多大」。)core/upload_file_wiring.py:104 附近有 except Exception 吞掉。要追:吞掉之後系統處於什麼狀態?是「這次上傳失敗」還是「靜默降級成沒有防護的模式」?(FR-085 C1 查過同目錄另一處,那次的結論是降級機制把 bug 藏起來,值得對照。)di_containers/upload_file/ 的接線 —— 哪些 adapter 被註冊、有沒有把「守門」這件事漏掉(B1 的⑤會查套件側缺守門的行為,本棒查宿主到底有沒有傳)。infra/upload_file/remote_agent_adapter.py(273 行)只讀不深追。 它是「把檔案存到客戶自己設備」那條路的轉接層。本棒只需確認它從哪裡拿憑證、以及有沒有明顯的憑證外洩;完整的遠端 agent 通道掃描屬 FR-077 的 CM-1594,不要在本棒重做。第一步:確認主 session 是 Opus 5 (1M context)(不是 Sonnet),讀過首腦手冊第二節與第十節(白話規則)。