⚠️ 歷史紀錄:本報告描述的問題已於 2026-11-07 全部修正並合回 Agent 主線(修正卡 CM-3559~3564、3573~3576、3584,驗收紀錄見母卡 CM-3507)。文中的檔名與行號是掃描當下(commit
bab2aa3)的版本,修正後已變動,請勿拿來定位現行程式。
這一棒沒有找到要處理的問題。 工具找到 0 條。卡片列的 6 個重點我逐條開檔看過,都不成立,或者只有很小的影響、不值得另外開卡(見下方「重點逐條人工查證表」)。要注意的是:工具的研究員一條候選都沒提出,三位檢查員就沒有東西可以投票,所以「0 條」的意思是「沒有東西可投」,不等於「證明乾淨」。
sbom-scan): SBOM 是「軟體物料清單」,也就是一份列出程式用了哪些第三方套件和版本的清單。流程是:使用者上傳源碼壓縮包(或一份現成的 SBOM)→ Agent 解壓 → 用 Syft 產出物料清單 → 用 Trivy、Grype、OSV-Scanner 三套工具,對本機的離線弱點資料庫(vulndb)比對已知漏洞。base.py 是所有 connector 的共同基底類別,__init__.py 是「工具代號 → connector」的登記表。範圍是 5 個檔,約 907 行:
sbom_scan.pysbom_tools.pysbom_coverage.pybase.py__init__.py為了查證呼叫端,我翻了範圍外的 3 個檔:guidant_agent/shared/archive_safety.py、common/util/scan_tools.py、guidant_agent/console/api/scan_routes.py。這些只為查證而讀,本身不當作發現。
| # | 這是什麼問題 | 出事會怎樣 | 要先有什麼才打得到 | 在哪裡 | 怎麼修 | 嚴重度 |
|---|---|---|---|---|---|---|
| — | 工具沒找到問題 | — | — | — | — | — |
沒有發現,這一節沒有內容。
| 首腦標的重點 | 人工結果 | 為什麼 |
|---|---|---|
① 源碼包從哪來、解壓、symlink(sbom_scan.py:157、:206) |
不成立 | 檔案從哪來: 先找本機上傳槽(find_local_input,用 agent_local_uid 找);找不到才用注入的 file_downloader 向主系統下載。識別碼: scan_uid 先過 SAFE_DIR_NAME 檢查,只收單層的安全名稱,才拼進路徑(:206-210)。下載落點: 外來檔名只取 basename,放在 0700 的暫存目錄裡( :248)。解壓: 走 archive_safety.extract_archive(:274)。tar 用標準庫的 filter="data",會拒收「絕對路徑或指到外面」的 symlink 和裝置檔;zip 的 zipfile.extract 根本不會建立 symlink。所以壓縮包裡放一個 -> /data/secrets 的 symlink,解壓這一步就被擋,不會被 Syft 讀進去。殘留: 只剩「指到包內」的 symlink,Syft 跟過去讀到的還是包內的檔案,沒有越界。 |
② tools、sbom_formats 有沒有白名單(:170、:182);Popen 的 argv 與 env |
不成立(附一個觀察) | tools: 不在 TOOLS 清單裡就直接 ValueError(:175-177),最後照固定順序重組。格式: 每一項都要對上 SBOM_FORMATS 的格式加版本白名單(:183-186);傳字串而不是陣列,會被逐字拆開,也一樣被拒。_BINARIES[tool]: 只用常數去查,不會被注入。argv: 全部是 list 形式、不經 shell。進命令列的只有白名單格式、工作目錄裡由程式自己產生的路徑,以及 --source-name;--source-name 是用 safe_source_name 清過的檔名,而且是獨立一個 argv 元素,不會被當成選項。env 觀察: offline_env 是複製整份 os.environ 再覆蓋離線設定(sbom_tools.py:50)。Agent 自己的環境變數會整份交給這四支隨版附帶的工具。工具本身是信任的程式,所以不算漏洞;若要收緊,可以改成只傳必要的變數。 |
③ scan_tool_path 怎麼找工具(sbom_tools.py:83-90) |
不成立 | common/util/scan_tools.py:19-31 的查找順序是:1. AGENT_SCAN_TOOLS_DIR 環境變數2. 隨版附帶目錄 3. /opt/guidant-agent/tools/bin4. 前面都找不到,才退回 shutil.which(也就是 PATH)要換掉工具,得先能改 Agent 的環境變數或可寫入安裝目錄,這等於已經拿到主機權限,不是新的攻擊面。 |
④ sbom_coverage.py 吃工具輸出的 JSON |
**不成立(附一個觀察) | 這支其實不讀 JSON**:它只走訪解壓目錄,os.walk 預設不跟隨 symlink;再看 requirements.txt 有沒有沒鎖定版本的套件。讀檔觀察: readlines() 會把整個 requirements.txt 讀進記憶體。上限是解壓總量(預設 500 MB),屬於有上限的資源消耗。真正吃 JSON 的地方: sbom_tools.py:207 的 osv_sbom 讀 Syft 產出的 CycloneDX 清單,大小跟著源碼包裡的套件數量長,同樣被解壓上限和 20 分鐘的掃描逾時框住。 |
⑤ base.py 共用參數過濾、帳密不進 log、報告遮罩 |
**不成立(屬設計缺口,已在 #223/#224 登記) | DetectionConnector.__init__ 只把 params、credentials 原樣存起來,沒有**共用的參數過濾,也沒有規定帳密不進 log;報告遮罩由各支 connector 自己處理。sbom-scan 本身不用帳密, format_failure_detail 只截工具 stderr 的最後 500 字。「在基底層加一道每支工具的參數白名單,一次修好 #223/#224」這個想法可行,但屬於修法建議,不是新的問題,所以不重報。 |
⑥ __init__.py 登記表與 TARGET_PARAM 對不對得上 |
**不成立(sbom-scan 部分) | 登記表有 9 個代號;scan_routes.py:37 的 TARGET_PARAM 沒有 sonarqube 和 sbom-scan。sonarqube: repo_url 沒過清冊,就是已登記的 B5 F2,不重報。sbom-scan: 它沒有網路目標,輸入是上傳的檔案,不連任何主機,所以本來就不需要過清冊。 舊 id 對照:** _LEGACY_TOOL_ID_TO_CODE 只有 4 筆,而且有註明「新工具不准加」,沒有錯配的風險。 |
verification.status 是 verified。研究員派出 1 位、回來 1 位,候選 0 條,面板 0 票。沒有東西可投,不等於乾淨。requirements.txt 整份讀進記憶體。工具和人工都沒有執行任何程式,也沒有實際打過任何攻擊,結論全部來自讀程式碼。
wf_6632477e-e9f6d1e6ca,branch ws-CM-3507-CM-3530,工作目錄沒有未提交的改動(clean)low(一位研究員加三視角面板;沒有盤點、威脅模型、廣度掃描);共 5 檔,耗時 423 秒verification 欄: status: verified、candidates: 0、panel_votes: 0、researchers_dispatched: 1、researchers_returned: 1、reason: nulldocs/security-scan/FR-177/runs/CLAUDE-SECURITY-20261106-035654/