本卡屬 FR-108(母卡見建卡後補號),第 2 棒:掃描基準(profile)CRUD/版本/fork/公版與租戶 scope、壓縮檔驗證、受限下載、cinc-auditor 解析子程序、分類骨幹、隨包七支轉換腳本。50 檔,只掃不修。
客戶可以上傳一包掃描規則(壓縮檔)或指定一個網址讓系統去抓,系統會解開、跑外部程式解析出規則清單,存成「基準」給掃描用;平台也有公版基準分享給所有客戶。這棒看四道門:壓縮檔會不會炸伺服器或寫到不該寫的地方、網址會不會被拿來打內網、外部程式吃到惡意檔會怎樣、公版基準誰能改。
整支套件「接收外部輸入」的路全在這裡,四個防護模組各自自陳了界線(archive 檔頭第 20 行、safe_http_fetch 檔頭「決策者裁不做白名單」)。這是與其他套件風險型態最不同的一棒。
common/detection_profile_archive.py)。自陳:副檔名→大小→magic→開檔→逐 entry(zip-slip/bomb 比 200 倍)。檔頭第 20 行自陳「bomb 檢查靠 entry 自報的 size 累加,是 header 值不是實讀值,理論上可被偽造」——驗這個理論上會不會變實際上:後續誰真的解壓(profile_extractor/inspec.py:361-403 _read_entries 用 zipfile/tarfile 讀全部 entry 進記憶體)、有沒有第二道實讀上限;_MAX_MANIFEST_DEPTH=1;.tar 用 offset 257 ustar 識別,tar 內 symlink/hardlink/device entry 有沒有擋(_assert_entry_safe)。common/safe_http_fetch.py)。決策者裁不做網域白名單,靠三條基本防護+兩條上限。逐條驗:169.254.169.254/localhost/私網段擋在哪一行、DNS 解析後的 IP 有沒有再驗(DNS rebinding)、自走重導向 3 hop 每一跳有沒有重驗目標;probe_url_validators 回給前端的內容會不會把內網回應帶出來;誰能建 url 型基準(租戶管理員即可,detection_profile_service.py:327 公版才要平台管理員)。common/profile_extractor/inspec.py:164-175、app/service/detection_profile_extraction_service.py:394-505)。subprocess.run 跑 cinc-auditor 吃使用者上傳的規則檔:參數怎麼組(有沒有 shell=True、路徑可控)、timeout、stdout 上限、暫存目錄怎麼清、_run_worker 是背景執行緒還是排程——用什麼身分(user_ctx 傳進去了嗎,_current_login_name() :665);_repack_flat 重打包時檔名 _normalize_name 有沒有洗乾淨。detection_profile_service.py:18-26/:310-430、common/guard.py)。公版 SYSTEM 寫入靠 _guard_system_writable→viewer_is_platform_admin()(service 層);SHARED 靠 assert_scope_writable。驗:15 條 profile route 只掛 require_license(沒有一條掛 detection-profile.* 四顆能力點——與 FR-098 第 80 項/FR-101 同款「宣告了不守」,確認後標同一產品決策題);fork(:430)與 copy_to_tool(:451)從公版複製到租戶時 tenant_id 從哪來;detection_profiles_select policy 含 scope='SYSTEM' OR …——SYSTEM 列的 tenant_id 是 ROOT,租戶能不能藉 SHARED 看到別家。DetectionProfileVersionSourceRoute :337-377 是 patch 不是下載?——確認這支到底做什麼;真正的下載在哪、以 version uid 取檔有沒有驗歸屬;_read_source_bytes(file_id) 用數字 id 查 upload_files——upload_files 剛在 2026-09-16 651e33c 補了 RLS,掃描版本 a6475b4 已含,驗它對這條路的實際效果)。detection_profile_taxonomy_*)。三支寫入掛 require_platform_admin_route(正確);detection_profile_taxonomies/_controls 兩張表零隔離——骨幹是全站字典(正確),_controls 是每個版本解析出來的規則清單(有主人,屬某租戶的基準版本)——驗 _controls 零隔離是不是漏了,讀取路徑 list_controls(version_uid) 有沒有先驗 version 歸屬。profiles/tools/*.py,含 gpo_extract.py 有 subprocess)。它們是出貨內容還是開發工具?有沒有被 runtime import;若只是工具,標「不構成攻擊面」即可。_resolve_credentials 解密租戶工具憑證明文交給 agent(主專案 detection_task_payload_provider.py+本套件 detection_orchestration_service.py:1397)。那條是 agent 控制面不驗身分的問題,撞到標「重複 CM-1595」,但本套件這側「憑證解密後的流向與落點」是新的觀察面。detection_executions/_groups/job_execution_detection_tools/_agents/tenant_detection_tool_configs 各 1 條 FOR ALL policy;detection_profiles/_versions 各 4 條)、9 張零隔離:detection_tools/detection_tool_param_schemas/detection_profile_taxonomies/detection_profile_controls(四張是碼表或公版內容,依「有沒有主人」判準可能正確)與 job_execution_comments/_devices/_org_units/_surveys(屬 flow-control 不在本套件)。8 顆能力點 is_platform 全 f。detection_tools 8 筆、tenant_detection_tool_configs 7 筆(1 租戶)、detection_profiles 11 筆(2 租戶)、detection_executions 76 筆。common/guard.py 與 api/guards.py 是「未接線 fail loudly」設計(_guard() 缺 adapter 直接 RuntimeError)——與 FR-098 A1 ⑤ 同款正面案例,驗證它真的做到即可,不要當漏洞報。