---
title: FR-177 總結報告（PM 版）：Guidant AI Agent 本體資安掃描
status: 🏁 25 棒 2026-11-06 全部驗收完；PM 版（不含程式位置）；工程師版在 Agent repo
---

# FR-177 總結報告：Guidant AI Agent 本體資安掃描

> 掃描時間 2026-11-05 23:30 ～ 11-06 05:00，25 棒全部完成。掃描對象：Agent repo `evidence-agent` 釘 commit `bab2aa3`（第二、三期因報告合回而落在 `3813abd`／`749d3b4`／`63334f4`，程式碼與 `bab2aa3` 相同）。工具：Claude Code 官方 `claude-security` plugin 0.12.0，每棒一位研究員讀全範圍、三位獨立檢查員對每條候選投票。首腦對每條通過的發現都開檔核對過行號與呼叫路徑；高風險那條四段逐行核對攻擊路徑。
>
> 這是 **PM 版**：講有什麼問題、多嚴重、為什麼、怎麼修的方向、先修哪些。**不含程式檔名與行號**（漏洞還沒修，位置不公開）。要看每條的確切位置與函式級修法，請看 Agent repo 內的工程師版 `docs/security-scan/FR-177/SUMMARY-engineering.md`。跨六輪掃描的累積總表在 [`security-scan-consolidated/`](../security-scan-consolidated/)。

---

# 🔴 結論：要修 1 件急的、12 件中等的，修法方向已定

**Agent 是我們裝在客戶自己機器上的程式。前六輪資安掃描（2026-09，140 輪）掃的全是主系統與套件，Agent 本體一個檔都沒掃過；這一次補上。**

| | 數量 | 一句話 |
|---|---|---|
| **高** | **1** | 主控台「手動掃描」可以手填任意檢測規則包的路徑，Agent 原樣拿去執行，**等於有「發動本機掃描」權限的人能在 Agent 主機上跑任意程式**（#223） |
| 中 | 12 | 8443 埠開一條空連線就能凍住 Agent、做壞的壓縮檔吃光記憶體、LDAP 來源可改成假伺服器冒充他人、登入入口不限大小、改工具位址會把舊密碼送到新位址、Agent 被拿來連清冊外主機（兩種路）、手動升級路徑以 root 跑未驗章的腳本、**三支掃描工具接頭連線不驗對方身分**（InSpec SSH 不驗主機指紋、連 ZAP 走明文、連 OpenVAS 不驗憑證）、私鑰建檔瞬間權限太寬 |
| 低 | 9 | 登入狀態該踢沒踢的三種情況、診斷包權限、總覽帶出掃描目標、ZAP 爬蟲範圍封口、DNS 探測可被卡死、代理帳密沒遮 |

**核實乾淨的部分，每一塊至少兩棒從不同角度看過**：自動更新鏈（下載→驗指紋→用現行版驗新版原廠簽章→擋降版，新版程式在驗章前一行都沒執行）、Ed25519 簽章核心與啟動完整性閘、8443 的身分驗證守門殼、Agent 對外連線的 TLS 驗證沒有任何關閉的路、瀏覽器直傳的一次性票券、本機登入的密碼雜湊與鎖定、祕密保管的加密。

**這一輪的方法論結果**：25 棒全部面板完整跑完、無一棒中斷、runner 無一棒缺交。這是六輪掃描以來第一次，原因是每棒壓在 1,000 行上下、且用工作坊的開場 prompt 自動啟動。

---

## 一、掃了什麼、怎麼切

Agent 本體 237 支 Python、約 27,400 行，加 3 支主機端升級腳本（bash）。按「客戶內網直接打得到的入口」優先，分三期：

| 期 | 棒 | 涵蓋 | 檔／行 |
|---|---|---|---|
| 第一期（8 棒） | A1～A8 | 註冊與憑證、8443 收指令、線上更新鏈、規則包解壓、簽章核心與啟動閘、主控台本機登入、LDAP 與網段白名單、證據檔直傳 | 63／8,500 |
| 第二期（9 棒） | B1～B8 | 主控台全部路由與聚合層、掃描任務執行與工具帳密、執行紀錄與上傳槽、目標清冊與回報、主系統通道與設定拉取、祕密保管與診斷包與裝置指紋、主機端升級腳本 | 71／9,300 |
| 第三期（8 棒） | C1～C8 | 各掃描工具的接頭（SonarQube、InSpec、Nmap、ZAP、OpenSCAP、OpenVAS、SBOM）與網路診斷十項探測——全部是 Agent 組參數去跑外部工具或連客戶主機的地方 | 33／8,300 |

沒掃、首腦用 grep 補查的：設定檔、依賴注入接線、錯誤碼表、各 port 介面、migration。

每棒的 scope 寫死在 Notion 卡上，研究員越界讀到的東西驗收時挑掉。

---

## 二、找到什麼：按嚴重度列

嚴重度判準：**高**＝不需要特殊前提就能拿到不該拿的控制權或資料；**中**＝要先有某個前提（已登入、特定權限、在內網特定位置）；**低**＝只能讓已經在裡面的人多留一會、或多看到一點。每條的「出處」指向逐棒報告與跨 arc 總表的項次。

### 🔴 高（1 條）

**#223 主控台手動掃描可手填任意 InSpec 規則包，Agent 原樣執行**

- **這是什麼問題**：主控台「手動掃描」頁選 CINC Auditor／InSpec 工具時，`profile` 欄位可以填任何路徑或網址。這個值一路傳到執行點都沒有人擋，Agent 就用它跑 `cinc-auditor exec <你填的東西>`。規則包本質是 Ruby 程式碼。
- **出事會怎樣**：填一個攻擊者自己寫的規則包網址，Agent 主機就執行了攻擊者的程式。Agent 主機上存著客戶所有掃描工具的帳密（SonarQube token、SSH／WinRM 帳密）、Agent 自己的私鑰、本機資料庫，全部讀得走。
- **要先有什麼才打得到**：主控台帳號有「發動本機掃描」權限、Agent 設好了 InSpec 帳密、目標清冊至少有一台主機。任何正常使用中的 Agent 都滿足。
- **在哪裡**：主控台路由層 → 本機掃描排程 → InSpec 接頭，四段都沒有擋，首腦逐行核對過。
- **怎麼修**：手動掃描只准選「主系統同步下來的規則包」，手填路徑一律拒收；同時把主控台的參數過濾改成「每個工具列舉可以收哪些欄位」，而不是現在的「只擋底線開頭」。
- **出處**：B5 F1（3:0）、B2 M1（3:0）、C2 F1 再確認。

### 中（12 條）

| # | 這是什麼問題（白話） | 出事會怎樣 | 要先有什麼 | 在哪裡 | 出處 |
|---|---|---|---|---|---|
| 225 | 對 Agent 8443 埠開一條 TCP 連線、不完成 TLS 握手，Agent 就卡住 | 主系統派工、重啟、升級、取檔全部停擺，直到連線斷或重啟服務；不洩資料 | 能連到 8443（客戶內網任何機器） | werkzeug 在接連線那條執行緒做握手且無逾時 | A2 F1（3:0） |
| 226 | 解 tar 壓縮檔時先把所有成員讀進記憶體數檔案，才查配額 | 一個做壞的小壓縮檔讓 Agent 整支當掉；更新包、漏洞庫、規則包、源碼包四條路都走這裡 | 能讓 Agent 解一個壓縮檔（主控台有掃描或更新權限） | — | A4 F1（3:0） |
| 227 | 只要有「設定」權限就能把 LDAP 來源改成自己架的假伺服器 | 冒充名單上權限更大的操作者登入，別人用 AD 登入時密碼也被收走 | 已有 configure 權限、名單上有權限比他大的人 | 兩支 PUT 都只要 configure | A7 F1（3:0） |
| 229 | 主控台登入入口收請求內容沒有大小上限 | 不用登入就能送幾 GB 把 Agent 記憶體吃光 | 來源在 8444 允許網段內 | 用 整包讀，沒掛 | B1 F1（3:0）、B3 人工 |
| 232 | 主控台改掃描工具的「位址」時，密碼欄留空就沿用舊密碼 | 有 configure 的人把位址改成自己的機器、按「測試連線」，客戶的 SonarQube token／OpenVAS 密碼就送過去了。**我們自己的資安需求 SR-06.3 寫「位址改了祕密要重填」，LDAP 那頁有做、這頁沒做** | configure 權限、該工具已存過帳密 | 沒傳 ， 的 永遠 False | B4 F1（3:0） |
| 224 | SonarQube 的 `repo_url` 不經過「Agent 准連哪些主機」的清冊檢查 | Agent 被當跳板對內網任意主機 `git clone`，錯誤訊息回給使用者可探測內網 | 有本機掃描權限、設好 SonarQube | 清冊只比對固定鍵名 | B5 F2、B2 M2、B6a F1、C1 F1（皆 3:0） |
| 233 | 清冊比對網址目標時查一次 DNS，掃描工具連線時又自己查一次，兩次可以拿到不同 IP（DNS 換綁） | ZAP 主動掃描（會送攻擊流量）打到清冊外的內網主機 | 能發動 ZAP 掃描、掌控一個網域 | 解出的 IP 不綁給工具 | B6a F2、C4 F2（3:0） |
| 234 | 用交付包**手動**升級 Agent 時，主機以 root 從新映像裡取出升級腳本直接執行，前面只比對包內自帶的指紋、沒驗原廠簽章 | 拿到偽造交付包的維運人員一執行，偽包的程式就以 root 跑在客戶主機上。**自動升級那條路沒這問題**：它先用現行版驗新版簽章才交棒（B8 逐行核時序） | 維運人員拿到並親手執行一個被換掉的交付包 | — | B7 F1（3:0）、B8 觀察 1 |
| C2-F2 | InSpec 用 SSH 連 Linux 目標主機時不檢查對方的主機指紋（SSH 用來確認「連到的真的是那台機器」的身分證） | 內網裡冒充目標主機 IP 的人拿到稽核帳號的密碼，或回傳假的檢測結果。**同一套程式裡 OpenSCAP 與 Nmap 兩個接頭都有做這個檢查，只有 InSpec 漏了** | 攻擊者在客戶內網、能搶到目標主機的 IP | 無任何指紋欄位； 只被 openscap、nmap 引用 | C2 F2（3:0） |
| 238 | Agent 連客戶的 OpenVAS 弱點掃描器時不驗 TLS 憑證 | 同網段做中間人的人拿走 OpenVAS 帳密，或回一份假的弱點報告讓 Agent 當證據上傳 | 能在 Agent 與 OpenVAS 之間做中間人 | 不帶 ，python-gvm 預設不驗 | C5 F1（3:0） |
| C4-F1 | Agent 連 ZAP 掃描器預設走明文 http；就算設 https，ZAP 官方 Python 套件寫死不驗憑證 | 在 Agent 與 ZAP 之間偷聽的人拿到 ZAP 的 API key（等於整台 ZAP 的遙控器）與登入後掃描用的目標網站帳密 | 能在 Agent 與 ZAP 之間的網路偷聽 | 沒 scheme 時補 、、 帳密送出處 | C4 F1（3:0） |
| 219 | Agent 註冊時私鑰與通行證檔「先建檔、寫完、再改權限」，建檔那一瞬間用系統預設權限（常是大家可讀）；改權限失敗時默默放過 | 同台機器上有普通帳號的人在那一瞬間讀到私鑰，就能冒充這台 Agent | 已在客戶機器上有帳號且憑證目錄可進 | 、 | A1 人工 M1（未經面板，首腦核對屬實）；判低～中 |

### 低（9 條）

| # | 這是什麼問題 | 位置 | 出處 |
|---|---|---|---|
| 220 | 主控台登入狀態只要一直在用就永遠不過期，主系統停權後 Agent 不會跟著踢 | — | A6 F1（3:0） |
| 221 | 在主控台改密碼，不會把同一帳號其他已登入的狀態作廢（命令列重設那條會） | — | A6 F2（3:0） |
| 222 | AD 帳號登入失敗時，名單上的人回應比較慢，量時間就能篩出哪些 AD 帳號能登入 | — | A6 F3（3:0） |
| 228 | 主系統縮減某人權限（人還在名單上）時，他正在用的登入狀態不會被踢 | — | A7 F2（3:0） |
| 230 | 下載診斷包只要「設定」權限，沒要求「下載檔案」權限 | — | B1 F2（2:1） |
| 231 | 總覽頁「正在執行」清單不看權限，一律帶出掃描目標 IP 與設備名 | — | B3 F1（3:0） |
| C4-F3 | ZAP 爬蟲範圍規則沒有在主機名結尾封口，`10.0.0.5` 的規則也會比中 `10.0.0.50` | — | C4 F3（2:1） |
| 239 | 網路診斷的 DNS 探測收回覆沒有總時限、不檢查回覆是誰送的，有人一直丟垃圾封包這次診斷就永不結束、之後所有網診卡住到重啟 | — | C7 F1（3:0） |
| 240 | 代理伺服器網址沒寫 `http://` 時，「遮帳密」函式把原字串連密碼整段吐回，進儀表板、報告、診斷包 | — | C8 F1（3:0） |

### 人工查到、判定不開卡的觀察（記錄用）

各棒 runner 照卡上「重點看什麼」逐條人工補查，另記下約 15 條「設計取捨」或「縱深防禦建議」，都不算漏洞：清冊接受 `0.0.0.0/0` 萬用網段（主系統本來就能列任何 IP）、舊清冊可回放（版本只比相同不比大小）、啟動閘不擋清單外多出的檔（要先有 root）、裝置指紋兩來源都讀不到時退化成固定值（靠主系統撞號偵測）、SonarQube 源碼包內的 `sonar-project.properties` 沒刪、ZAP 逾時使用者可改到沒上限、ZAP 報告原樣上傳不遮蔽、票券重放紀錄只在記憶體（重啟即忘，註解寫明刻意接受）等。全部列在各棒報告的「重點看什麼逐條人工查證」表與總表 §3.1 各項尾註。

---

## 三、四個反覆出現的模式

**① 路由層把使用者輸入原樣交下去，沒有每工具／每欄位的白名單**。#223、#224、#229、#232、#233 五條根因相同：主控台路由只擋底線開頭的參數鍵、清冊只比對固定幾個鍵名，其餘什麼都放。第三期 C1～C4 從 connector 內部再看，確認 connector 自己也沒有再擋一層。**修一處（路由層改成每工具列舉可收的鍵）就能一次關掉五條。**

**② 「位址可以改，但沒有要求重填祕密或提升權限」**。#227 LDAP 來源與 #232 工具位址都是同一件事：改了連線對象，舊的祕密會自動送到新對象。我們的資安需求 SR-06.3 明寫要擋，LDAP 設定頁有擋、工具設定頁沒有，是同一個人寫的兩頁行為不一致。

**③ 「該踢的時機沒踢」**。#220、#221、#228 三條都是登入狀態的生命週期：沒有絕對上限、改密碼不撤銷、縮權不撤銷。同一支  改三處。

**④ 「連外部工具時不驗對方身分」**。C2-F2 InSpec SSH 不驗主機指紋、C4-F1 連 ZAP 明文且不驗憑證、#238 連 OpenVAS 不驗憑證，三條都是 Agent 對客戶自備掃描工具的連線沒有「確認對方真的是那台」。Agent 對**主系統**的連線這點做得很嚴（A1／B6b 核實無任何關閉驗證的路），對**掃描工具**卻全漏，是同一支程式裡兩套標準。

另外兩個單點但要特別講：**#234 手動升級路徑**與自動路徑的防線不對稱，自動路徑三道鎖都在、手動路徑漏了驗章那一道；**C2-F2 InSpec 不驗主機指紋**與 OpenSCAP／Nmap 不對稱，三支同型接頭只有一支漏。這兩條都是「同一件事做了兩遍、一遍對一遍錯」，修法是對齊到對的那一邊。

---

## 四、建議怎麼修：六張修正卡（方向）

併卡原則：同一根因併一張、同一支程式併一張；嚴重度高的先。每張的函式級修法在工程師版。

| 卡 | 修什麼 | 方向 |
|---|---|---|
| 🔴 ① 主控台與清冊的輸入白名單 | #223 高、#224、#229、#232、#233、#231 | 主控台路由改成「每個工具列舉可收的欄位」；手填規則包拒收；清冊改成預設拒絕、網址目標只收 IP；登入入口加大小上限；改工具位址強制重填密碼 |
| ② LDAP 設定只准本機管理員 | #227、#230 | 改 LDAP 來源與伺服器的權限從「設定」提升為本機管理員；一改就踢掉所有 AD 登入 |
| ③ 登入狀態生命週期 | #220、#221、#228、#222 | 登入狀態加絕對上限；改密碼踢掉其他登入；主系統縮權也踢；AD 登入失敗補到固定時間 |
| ④ 手動升級路徑補驗章 | #234 | 手動升級比照自動升級，先用現行版驗新版的原廠簽章才執行新版腳本 |
| ⑤ 兩條 DoS 與兩條可用性 | #225、#226、#239、#240 | 8443 握手加逾時並移出接連線的執行緒；壓縮檔逐成員計數；DNS 探測加總時限；代理帳密遮罩補 scheme |
| ⑥ 接頭連線驗對方身分 | InSpec 主機指紋、ZAP 加密、OpenVAS 憑證、ZAP 爬蟲封口 | 三支掃描工具接頭比照 Agent 對主系統的做法，連線前確認對方身分；工具設定加「CA 憑證」欄位一次給三支用 |

零碎：#219 私鑰建檔權限併進 ①或 ⑤。

**要寫測試**：卡 ①、②、⑥ 屬認證／授權核心，要寫單元測試並附突變測試（把修法註解掉要紅）。**手測**：卡 ① 在 DEV Agent 主控台填外部網址當規則包要被擋；卡 ④ 在 190 測試機用改過一個 byte 的假交付包跑升級要被擋。

## 五、先修哪些、為什麼

1. **卡 ①（含 #223 高）先做**。它是唯一不需要特殊位置、只要一個正常權限的帳號就能拿到 Agent 主機控制權的；而且一張卡關掉六條。
2. **卡 ④ 與卡 ⑥ 次之**。#234 與 C2-F2 都是「同型的三條路，兩條對一條錯」，修法是抄對的那一邊，工作量小、風險低，但後果（主機 root、客戶稽核帳密）大。
3. **卡 ② 要先問產品**：LDAP 設定收到只准本機管理員，會不會擋到客戶正常的 IT 管理流程。
4. **卡 ③、卡 ⑤ 可排一般迭代**。

**落地版判準**：上面全部是落地版客戶內網打得到的，沒有「只影響 SaaS 可暫緩」的項目。

---

## 六、這次檢查可信到什麼程度

### 第一層：「這些問題是真的嗎」→ ✅ 可信

- 每條通過的發現都經三位獨立檢查員從「打不打得到」「後果多大」「有沒有別的防線」三個角度投票；25 棒 32 條候選、96 張票全部投出、零漏投。通過 22 條（3:0 為主，三條 2:1）、否決 10 條。
- 首腦對每條通過的發現開檔核對；#223 四段逐行核對攻擊路徑；#234 核對手動路徑與自動路徑的時序對照。
- 唯一例外：#219 是 runner 人工發現、未經面板，首腦核對程式邏輯屬實，但實際風險取決於安裝腳本有沒有先鎖目錄（沒查）。
- 兩處「採信檢查員讀第三方套件原始碼」：C2 train-core 預設不驗 host key、C4 zapv2 寫死 `verify=False`，首腦沒有重讀 gem／site-packages。

### 第二層：「是不是只有這些」→ ⚠️ 中等，不能說「掃乾淨了」

- 用的是 low effort：每棒一位研究員讀全範圍、不做威脅建模、不做廣度掃描。工具有隨機性，同一份程式再掃可能找到不同的東西。
- 六棒工具零候選（A1、A3、B6b、B8、C6，與否決後歸零的 A5、A8、C3）：`verified` 在那裡的意思是「沒東西可投」，不是「有人確認乾淨」。這五棒靠 runner 照「重點看什麼」逐條人工補查，每棒補查 6～8 項並寫下結論。
- 全部結論來自讀程式碼，**沒有執行任何程式、沒有實際打過**。#225（8443 握手卡住）、#226（tar 計數吃記憶體）這類 DoS 是讀 werkzeug／tarfile 原始碼推論的，沒有實測。

### 比前六輪可信的地方

- 25 棒全部跑完，無一棒面板中斷、無一棒 runner 缺交，首腦不必補寫任何一份報告（前六輪首腦補了十一次）。
- 每棒都有「重點看什麼逐條人工查證」表，「讀過但沒報」與「根本沒讀到」分得開。

---

## 七、這次換到的三條經驗

**① 工作坊可以跑掃描卡**。`claude-security` 只接受使用者回合的啟動句，前六輪都要決策者親手打；這次工作坊加了「每張卡一支開場 prompt 覆寫檔」，把啟動句當小弟 session 第一句送進去，25 棒全部自動啟動。工作坊的停滯判定（session busy 就不判卡死）也在真掃描上驗過。

**② 全中文 docstring 的程式，安全線是 1,000 行不是 2,000**。Agent 的註解密度是英文碼的兩三倍 token，第一期按 1,000 行切，25 棒零看門狗誤殺；第三期 C1 單檔 1,711 行、10,364 個中文字也跑完了（研究員 2/2、零 failed），C2 單檔 1,050 行、C8 十檔 1,291 行也都零 failed，表示「單檔一次讀完不追接縫」比行數更關鍵，並行四棒也沒影響。

**③ 人工補查抓到的不比工具少**。工具通過 19 條，runner 照首腦列的重點人工補查另抓到 #219 一條中、約 15 條觀察，並且把五棒工具零候選的範圍填上了「讀過」的證據。「重點看什麼」是這套方法裡成本最低、回報最高的一段。

---

## 八、第三期八棒看到什麼

第三期掃的是 Agent 組參數去跑外部工具的地方。首腦開卡前最擔心的三件事，結果如下：

| 擔心的事 | 結果 |
|---|---|
| 遠端字串指令（Nmap／OpenSCAP 在客戶主機上以 `sudo` 跑）有欄位漏 `shlex.quote` | **不成立**。C3／C5 逐欄核對，三個值全部 quote；`sudo` 只在 syn 掃描 |
| 網路診斷探測把使用者填的目標原樣進 argv，`-` 開頭被 ping 當成選項 | **不成立**。進探測前一律先過 `ipaddress.ip_address()`，只有合法 IP 才往下走 |
| 診斷報告把探測原始輸出渲染成 HTML 沒跳脫 | **不成立**。一律 `html.escape` 且報告不存 `.html` |

真正找到的是另一族：**三支接頭連客戶自備的掃描工具時不驗對方身分**（InSpec 主機指紋、ZAP 明文、OpenVAS 憑證），加上兩條低風險的可用性問題（DNS 探測可被卡死、代理帳密沒遮）。C1 SonarQube 與 C6 SBOM 在工具層淨新增零，人工補查各記了三條不開卡的觀察。

Semgrep 事前掃整個第三期範圍只命中一條（程式 subprocess 吃 env），**第三期六條發現沒有一條是規則掃描器抓得到的**，全部是「程式寫法正確（list argv、quote 過）但對象錯或少一道驗證」這類要靠讀程式才看得出的問題。

---

## 九、交付狀況

| 項目 | 狀態 |
|---|---|
| 逐棒報告 25 份 | 正本 Agent repo `docs/security-scan/FR-177/`，複本本資料夾 [`reports/`](reports/) |
| 工具原始產物（run 目錄）25 份 | `security-scan-consolidated/runs/agent/` |
| 跨 arc 總表登記 | §0.5 Agent 一列、§1 165 輪、§3.1 #219～240 |
| Notion | 母卡 CM-3507；子卡 25 張（CM-3508～3532）全部「驗收通過待確認」，Done 由決策者按 |
| 修正卡 | **未開**，等決策者裁第四節六張的併法與第五節順序 |
| 本報告 | PM 版（本份，無程式位置）；工程師版（含檔名行號與函式級修法）在 Agent repo `docs/security-scan/FR-177/SUMMARY-engineering.md`，不上站 |

### 等決策者裁的事

1. **#223 要不要在第三期驗完前就開修正卡**（建議：要，它不等其他條）。
2. **第四節六張修正卡的併法與第五節順序**，裁了首腦開卡進工作坊。
3. **卡 ② LDAP 設定收到只准本機管理員**是否符合客戶 IT 流程。
4. **逐棒報告 25 份含未修漏洞的檔名與行號，複本目前在 `feature/FR-172` 分支的 `docs/features/FR-177/reports/`**，合回 main 會隨需求文件站上線。總結報告已拆成 PM 版（上站、無行號）與工程師版（Agent repo、不上站）；逐棒報告複本要不要也從 `docs/features/` 拿掉、只留 Agent repo 正本，請裁。
