本卡屬 FR-086(母卡 CM-XXXX,建完補號),第 1 棒:套件的 HTTP 邊界與契約(jedi monorepo)。只掃不修。 建議最先跑。
掃 jedi-file-upload 套件的 api/+app/+ports/+common/+plugin.py 共 35 檔。這是檔案功能的對外門面:使用者上傳檔案、下載檔案、預覽檔案、以及跟系統要一張「短期下載憑證」,四條路都從這裡進來。要找的是:能不能把檔案寫到不該寫的地方、能不能下載到別人的檔案、檔名與大小有沒有把關。只找問題、不修問題。
四條對外路徑在同一條呼叫鏈上(收請求 → 組路徑 → 存檔 → 回應),切開會斷。而首腦盤點時看到的三個最直接的疑點全部落在這一棒(見下①②③)。這是整個 arc 風險密度最高的一塊。
首腦與偵察 agent 讀過程式碼後的起點,未經驗證。工具不會照這份清單走(連續五個 arc 如此),工具沒答的你要自己開檔查,並在報告標明「(工具未報,人工查證)」。
api/routes/upload_file_route.py:101:save_dir = str(os.path.join(payload.get('upload_type'), payload.get('uid'))),這兩個值來自請求的 multipart JSON part、完全由呼叫端填,而首腦沒看到任何 ../ 過濾或路徑正規化。要追:(a) payload 的 schema 有沒有對這兩個欄位做格式驗證(只允許特定值?正規表示式?);(b) 這個 save_dir 一路傳到哪(file_upload_service.upload_files → 哪個 adapter),中途有沒有人正規化;(c) 傳 upload_type="../../etc" 會發生什麼。同一支檔案 :134 有同款寫法,一起看。api/routes/upload_file_route.py:150-156:/file/access-token/<uid> 只掛 @auth_required,拿到 uid 就呼叫 signed_token_issuer(..., resource_uid=uid) 簽發,中間沒有任何「這個檔是不是你的」檢查。要追:(a) 簽出來的憑證帶不帶租戶綁定?(首腦只讀到它比對 resource_uid);(b) 拿這張憑證去下載,下游還會不會再檢查一次歸屬;(c) 若都不會,那這支端點等於自助發放跨租戶下載憑證。jedi-iam/jedi_iam/authz/signed_token.py:155-163:帶 st 參數走憑證軌,沒帶就退回 verify_jwt_in_request()——等同「任何登入者都過」。要追:下載端點(:170 附近的 UploadFileDownloadRoute)與預覽端點在 st 缺席時,還有沒有別的地方檢查歸屬?(這一項要跨讀 jedi-iam 那支,屬必要追脈絡,報告標明即可。)common/utils/file_utils.py:16:upload_file_extension = file.filename.split('.')[-1] 直接取使用者給的副檔名拼進存檔名。要追:(a) 有沒有副檔名白名單?(b) 有沒有 secure_filename 之類的正規化?(c) 有沒有單檔大小上限或檔數上限(首腦全鏈路沒找到,只有全域的 MAX_CONTENT_LENGTH 50MB,那是 CM-1587 定的、擋的是整個請求);(d) file.filename 含 ../ 或空副檔名(split('.')[-1] 會取到整個檔名)時各走哪條。api/__init__.py:59-76 的 guard 全部由宿主注入,套件側零判斷。要追:缺守門時是 fail-open 還是 fail-closed(拒絕掛載?還是靜默掛上一個沒防護的端點)?對照組:FR-081 的 jedi-issue 會 raise RuntimeError(好),FR-082 的 jedi-ai-bot 只靠 dataclass 必填欄位擋。這支是哪一種?plugin.py 的每一個預設值 —— 逐項問「這個預設是出錯就放行還是出錯就擋下來」。特別看檔案存放位置、允許的儲存後端、以及任何跟安全有關的開關。app/ 那層的用例編排 —— 上傳與下載的 app service 有沒有做歸屬檢查,還是整個信任 route 層?(若 route 層也沒做,那就是兩層都沒人做。)infra/models/upload_file.py 無 tenant 欄位,migration 檔頭自陳「本表沒有多租戶欄位……租戶隔離由『檔案的持有者資源』那一層負責」)。意思是資料庫層對這張表沒有任何隔離兜底——所以應用層的歸屬檢查是唯一防線,這正是①②③要查的。.env/憑證:本棒範圍內若撈到憑證,照實記並標明;套件根目錄的設定檔不在本棒 scope。第一步:確認主 session 是 Opus 5 (1M context)(不是 Sonnet),讀過首腦手冊第二節與第十節(白話規則)。