本卡屬 FR-077(母卡 CM-PARENT),第 3 棒:主專案 BE 的 agent 宿主接線(scanRoot 是 BE repo,不是 jedi monorepo)。只掃不修。
前兩棒掃的是套件本身。但套件被設計成把所有安全決策外包給使用它的產品——套件說「管理端點要掛什麼守門?你給我」「認證設定從哪來?你給我」「agent 認證要不要開啟?你決定」。真正的答案在主專案這 17 個檔裡。
用 claude-security plugin 掃這 17 檔並產出報告。只找問題、不修問題。
檔少但密度最高(17 檔 881 行)。規模與 FR-075 的 S1(11 檔)、FR-076 的 L1(10 檔)同級——那兩棒分別產出 8 條與 3 條發現,是全部十一棒裡密度最高的兩棒。原因相同:這種「接線層」每一行都在做安全決策。
獨立一棒是因為 repo 邊界:掃描的 scanRoot 只能指一個目錄,主專案在 compliance-manager-be、套件在 jedi monorepo,跨不了。
出問題會怎樣:套件的守門再嚴,宿主接錯線就等於沒有;套件的預設值是 mode="none"(不加認證),只要宿主沒正確組出 settings,整條 agent 鏈就跑在無認證狀態。
這些是首腦讀過全部程式碼後認為最容易出事的地方。是思考起點不是檢查清單——掃完後照這個自己追。
admin_required 到底疊了什麼(api/remote_agent/__init__.py)。它是 jwt_required() → require_license("remote-agent-manage") → require_capability("remote-agent-manage.create") 三層。套件的 admin_required 是單一 decorator、不區分讀寫,所以唯讀端點(列表/detail)現在也吃 .create 這顆 capability。註解說「方向上是收緊不是放寬」——驗這句話:require_capability 的實作(common/authz/)在什麼情況下會放行?require_license 在 license 缺失/過期時是 fail-open 還是 fail-closed?三層的順序有沒有影響(例如 jwt_required 之前就被短路)?plugin.py 的 _guard() 只把 decorator 套到 get/post/put/delete/patch 五個 method 上——BE 這邊掛的 Resource 有沒有其他 method?api/remote_agent/routes/agent_file_route.py)。這支端點沒有掛任何 decorator(不在套件的 ROUTE_TABLE 內,由 create_module() 直接 Api(bp).add_resource(...))——所以它是完全公開的 HTTP 端點,身分靠 X-Agent-Uid header 自報,授權完全依賴 AgentFileAccessService(在 jedi-detection,屬 R2)。本棒要驗的是宿主側:這條 route 掛上去時有沒有任何守門?Provide[Containers.detection_orchestration_container.agent_file_access_service] 這個 DI wiring 正確嗎(拿到的是不是有正確 session context 的實例)?send_file 用 download_name=file_name ——file_name 來自 DB 的使用者上傳檔名,有沒有 header injection/路徑穿越?common/util/agent_auth_settings.py,40 行)。這支是整條鏈「安不安全」的總開關——它決定 mode 是 "none" 還是 "full"、CA 與金鑰路徑指到哪。要追:AGENT_AUTH_MODE 沒設時是什麼(套件預設是 none=不加認證)?路徑類變數沒設會怎樣(sign_csr 會 ValueError 但 register() 只在「有 CSR」時才走到那裡)?.env 與 config/config.py 的預設值是哪一邊贏?部署文件有沒有寫這些變數必填?這裡是「安全預設」問題的核心落點。infra/upload_file/remote_agent_adapter.py,273 行,本棒最大一支)。這是雲端對 agent 做 upload/download/delete/PDF 的實作,也是 FR-039 memory 說「只有 adapter 一路是對的,其餘都要照抄它」的那一份。要看:build_cloud_mtls_context() 怎麼用、JWT 的 op claim 怎麼組(有沒有把使用者可控的字串串進去)、URL 怎麼組(base_url 是 agent 自報的 → SSRF/路徑穿越)、失敗怎麼處理(有沒有 fallback 到不驗證的路徑)、有沒有把憑證內容或 JWT 寫進 log。app/remote_agent/adapter/lazy.py + detection_task_payload_provider.py + detection_lifecycle_listener.py)。lazy.py 的存在是因為 create_module() 跑在 blueprint 載入迴圈裡、此時 DI container 還沒設定好。要問:延遲解析失敗時會怎樣?套件那邊寫著「三個 port 都可以不注入,會優雅降級」——若 lazy proxy 解析失敗時表現得像「沒注入」,那就是靜默降級(心跳照跑但待辦回空、或 lifecycle 編排整個不執行)。detection_task_payload_provider.py(125 行)是組派工 payload 的地方——套件 port 的 docstring 說裡面會放「解密後參數、憑證、限額」,逐行確認解密出來的憑證怎麼處理、會不會落 log、限額是怎麼算的。di_containers/remote_agent/remote_agent_containers.py 100 行、di_containers/agent_task/agent_task_containers.py 40 行)。CLAUDE.md 有明文鐵則:repo 不可註冊成 Singleton 且 __init__ 不可 self.session = get_session()(實例化早於 @transaction 開 scope → 500)。這裡的每個 provider 是 Factory 還是 Singleton?若 service 是 Singleton 而它持有的 repo 有 session 狀態,跨請求會共用嗎(跨租戶資料外洩的典型形狀)?infra/remote_agent/recon_query_adapter.py,34 行)。它回「這個 base_url 上有哪些檔案」給 reconcile()。要看:查詢用 base_url 字串比對嗎?有沒有帶 tenant?(若沒有,管理員對自己的 agent 觸發對帳時,會不會列到別租戶掛在同一個 base_url 的檔案。)本範圍從未被掃過——security-scan-2607 只掃主專案 BE/FE,但那是 2026-07,api/remote_agent/ 這套接線是 FR-069 P4 套件化之後才變成現在的形狀(原本是 blueprint + 15 條 route 直接註冊)。