Guidant AI 資安檢視 · 模組報告
系統對外講話的嘴巴——寄稽核提醒信、推 Discord 與 Telegram 訊息。最受關注的一條是「寄測試信」那個按鈕:寄信設定全系統只有一份、存在最上層,而「改寄信設定」的權限下放到各個下層客戶,所以下層的管理員可以按一下,把上層那組郵件帳密導到自己的機器上——這條已裁定由客戶自行管控權限,程式面加強了「換主機要重填密碼」。四條發現裡,寄信的三條已處理,剩「測試 Discord 群組」可當內網探測器那一條(低)未修。
系統要通知人的時候——寄稽核提醒信、把流程事件推到聊天群組——走的都是這塊。它管三條通知管道:
| 管道 | 需要保管什麼機密 |
|---|---|
| 寄信 | 郵件伺服器位址 + 帳號 + 密碼 |
| Discord 群組 | 一組專屬網址(誰拿到誰就能以我們的名義在那個群組發文) |
| Telegram | 機器人通行證(拿到即可冒充那隻機器人) |
三條管道有同一個共同點:都要保管客戶填的機密,都要主動對外連線。
保管機密 → 有「機密怎麼被讀出來」的風險。 主動連外 → 有「被騙去連到別的地方」的風險。
檢視期間:2026-09-08(單日完成兩輪)|範圍:48 個檔案(模組本體 30、主系統接線 18)|共 2 輪
原始技術報告放在需求中心的 FR-078 站,檔名見下表最後一欄。那裡有每一輪的完整技術細節、檔案清單與逐條推理,供需要深究或稽核抽查時查閱。
| 輪次 | 查什麼 | 檔數 | 覆核投票 | 結果 | 原始報告檔名 |
|---|---|---|---|---|---|
| N1 | 模組本體——三條管道怎麼存機密、怎麼對外連線 | 30 | 6 票全投完,兩條都 3 票一致 | 通過 2 條,都在同一支檔案裡 | scan-N1-package-core |
| N2 | 主系統這端怎麼把它接上來——尤其是「測試連線」那些按鈕 | 18 | 23 票全投完 | 通過 6 條(範圍內 2 條,另 4 條是順手撈到的密碼外洩) | scan-N2-host-wiring |
這是整批檢視裡第一次覆核完整跑完
在此之前的那一輪(遠端代理程式第一輪)覆核程序全部因為用量超標被中斷,一票都沒投出來。這一輪是第一次拿到完整紀錄,而且不是靠運氣——是把範圍縮小到 30 個檔以內換來的。
覆核者也沒有敷衍了事:他們把系統底層負責寄信與加密的那幾段現成程式逐行讀出來,證明「不帶設定的加密連線確實不驗對方身分」,不是照單全收提報者的說法。
第二輪中途撞到用量上限,但處理方式是對的
第二輪驗到一半撞上用量上限,有一條的三位覆核者只回來兩位。工具沒有拿兩票充數——它把那一條整條作廢、交給下一輪用完整三人重新投一遍。
所以票數是 23 不是 21:多出來的兩票,正是第一輪那條作廢掉的。「續投」不是補一張票進去,是整條重來——因為第三票如果在已知另外兩票結果的情況下投,性質就完全不同了。
三件沒查到、不能當作乾淨
排序按風險,同風險的同一類排在一起。「出事會怎樣」那欄講的是業務影響——誰受影響、損失什麼,不是技術現象。
| # | 問題 | 風險 | 分類 | 出事會怎樣(誰受影響) | 怎麼修 | 狀態 |
|---|---|---|---|---|---|---|
| 1 | 「寄測試信」會把系統存著的那組郵件密碼,送到按鈕操作者自己填的那台主機 | 🟡 中 | 密碼外流 | 寄信設定全系統只有一份、存在最上層;而「改寄信設定」這個權限下放到各個下層客戶,所以下層的管理員可以把上層那組郵件帳密導到自己的機器上。拿到之後能用那個身分對外寄信,而且會通過寄件人驗證——收件人完全看不出是偽造的。在我們自己營運的多租戶環境裡,上層就是我們公司;落地安裝版裝好時這一頁是空的、帳密由客戶自己填,外流的是客戶自己那組 | 由客戶自行管控——寄信設定屬最上游帳號的權責,要不要把這個權限下放給子單位是客戶自己的決定。程式面可順手加強一項:測試連線時目標主機換了,就不沿用存著的密碼、要求重填 | 🚫 裁定不修(權限面由客戶自行決定);程式面加強已做——伺服器位址或連接埠跟存著的不一樣時,不沿用存著的密碼、要求重新輸入(CM-2111)。權限面由客戶自行決定。 評為中風險的理由:外流的是同一家公司內部上層的帳密,範圍縮在單一客戶內部,與其他「同一家公司內部越權」的條目同一個量級 |
| 2 | 寄信失敗時,把整組郵件設定原樣寫進系統紀錄檔——那組設定裡有密碼 | 🟡 中 | 敏感內容寫進日誌 | 看得到系統紀錄的人就等於拿到密碼——維運人員、能查資料庫的人、外部紀錄收集服務的管理員,這些人遠多於被授權改郵件設定的人。而且不需要攻擊者做任何事,寄信失敗一次就會發生(密碼填錯、網路抖動都算)。⚠️ 共用地基那道密碼遮蔽蓋不到這裡,實跑驗過,密碼一個字都沒被遮掉 | 錯誤訊息只印錯誤本身,不要把整組設定丟進去 | ✅ 已修——失敗紀錄只記伺服器位址、連接埠與錯誤類別(CM-2111)。主系統掃描又從系統診斷包那一端撞到同一件事(總表第 207 項),不另列;它暴露的那種密碼寫法已併進診斷包遮罩那張卡一起修好(8-B,CM-2212,1.21.0 出貨) |
| 3 | 連郵件伺服器時「有加密但沒認人」——對方拿一張隨便自簽的證明來,系統照單全收 | 🟡 中 | 密碼外流 | 除了同樣洩漏郵件帳密之外,每一封信的內容都會落到攔截者手上——包含登入用的一次性驗證碼與新帳號的初始密碼信。等於帳號被接管的材料整批送出去。這條要成立,攻擊者得先在我們與郵件伺服器之間的網路路徑上(郵件服務在外部雲端時比較容易做到) | 設定頁加「驗證伺服器憑證」開關與信任憑證欄位;新建設定預設要驗 | ✅ 已修——新建/重存的設定預設驗證;升級前的既有設定維持不驗,設定頁頂部提示建議開啟(CM-2111) |
| 4 | 「測試 Discord 群組」填什麼網址就打什麼,系統不限制目標 | ⚪ 低 | 外部送什麼就收什麼 | 拿我們的伺服器當跳板去探測客戶內網——哪台機器活著、哪個服務開著。按得動的人比「寄測試信」更少:要有通知設定的權限,還要是帳號層的最高管理員。因為回應內容不會送回給操作者,所以偷不到資料、只能探測,風險因此評為低 | 兩層一起做:① 擋掉指向內網的位址;② 只允許已知的通知服務網域(Discord 那支就只能打 Discord)。設定畫面完全不動 | ⬜ 未修(原工單 CM-1605 已隨 09-21 統一派工作廢,目前沒有修正卡,待決策者裁定是否排入) 已核對:測試與正式發送都直接打填入的網址,沒有擋內網、也沒有限定網域 |
這四條跟寄信通知沒有關係——是檢視時順手做的密碼掃描撈到的。列在這裡是為了完整。
| # | 問題 | 風險 | 分類 | 出事會怎樣(誰受影響) | 怎麼修 | 狀態 |
|---|---|---|---|---|---|---|
| 5 | 一個測試用設定檔被推上版控,裡面是四把真的對外 AI 服務金鑰 | 🟠 高 | 密碼外流 | 直接的財務損失——任何拿得到程式庫的人都能用我們公司的帳號呼叫那些服務;其中一把還能讀走服務端存的執行紀錄,裡面例行含有客戶資料 | 撤銷重發、把檔案撤出版控 | ✅ 已修正——金鑰已撤銷換發,版控殘留字串已清(CM-2048,commit e8e134a4e) |
| 6 | 同一個檔案裡還有三樣東西:簽發登入憑證的金鑰、資料庫密碼、檔案儲存服務的金鑰。三樣的嚴重度不同,分項如下 | ⚪ 低 (三項同級,理由見下) |
密碼外流 | ① 簽發登入憑證的金鑰:拿到它就能自己偽造一張管理員身分的登入憑證,不需要密碼也不需要雙因子。 ② 資料庫密碼、③ 檔案儲存服務的金鑰:拿到就能直接讀寫資料。 🔴 三樣都只影響我們自己的開發機——安裝程式每裝一套都會各自隨機產生新的一份,所以外流的這三樣不會跟著出貨到任何客戶。影響範圍從「每一套裝出去的都中」縮成「我們自己的開發環境」 |
同上 | ✅ 已修正——三樣都已撤銷換發,版控殘留字串已清(CM-2048,commit e8e134a4e) |
| 7 | 一支產生文件的腳本,把客戶展示環境的完整資料庫連線資訊(含密碼)寫死在程式碼裡 | 🟡 中 | 密碼外流 | 可以直接連進客戶會看到的展示環境資料庫——那個環境依規定等同正式環境 | 改成從環境設定讀取 | ✅ 已修正——該組密碼已換發,版控殘留字串已清(CM-2048,commit e8e134a4e) |
| 8 | 系統管理員帳號的密碼寫死在三支腳本裡,其中兩支寫成「環境變數沒設就用這個」——而那個「這個」就是真密碼 | 🟡 中 | 密碼外流 | 拿到程式庫就等於拿到一組可用的管理員帳密。變數忘了設時會靜默用真密碼,操作的人不會被告知 | 同上 | ✅ 已修正——該組密碼已換發;兩支「環境變數沒設就用真密碼」的腳本改成沒設就中止並提示,版控殘留字串已清(CM-2048,commit e8e134a4e) |
這四條都與其他模組頁重疊,問題總表請只算一次
所有外流的通行證、金鑰、密碼都已經撤銷或換發完畢,版控裡的殘留字串也已由 CM-2048 清掉。
下面只展開需要你自己判斷、或容易被誤解的幾條。 其餘的修法明確,看上面表格的「怎麼修」那一欄就夠了——沒有展開不代表沒查,也不代表不重要。
郵件設定頁有一個「寄測試信」按鈕。使用者不改密碼欄位的時候,系統會從資料庫撈出存著的那組真密碼,配上使用者這次送過來的設定去試寄。
問題在於——伺服器位址那一欄也是使用者填的。
所以整件事變成:
使用者填一台自己控制的主機位址 → 密碼欄留空不改
↓
系統:「好,我用存著的真密碼去連你指定的那台機器」
↓
使用者在自己的機器上收到那組存著的郵件帳號密碼
寄信設定全系統只有一份、存在最上層;而「改寄信設定」這個權限下放到各個下層客戶。所以下層的管理員,可以把上層那組郵件帳密導到自己的機器上。
外流的到底是誰的帳密,要看產品裝在哪裡:
| 產品裝在哪裡 | 最上層是誰 | 外流的是誰的帳密 |
|---|---|---|
| 我們自己營運的多租戶環境 | 我們公司 | 我們公司對外寄信的那一組 |
| 客戶自己機房的落地安裝版 | 客戶自己的總管理帳號 | 客戶自己填進去的那一組 |
落地安裝版裝好的時候,這一頁是空的。 出貨的初始資料只建立「改寄信設定」那四個權限與選單,一筆寄信設定的資料列都沒有——帳密全部由客戶自己填。
持有「改寄信設定」這個權限的角色有 9 個,橫跨最上層與 7 個業務客戶;程式裡也寫明這個權限就是要下放給業務客戶的管理員。
裁定:寄信設定由客戶最上游的帳號自行管控,要不要把這個權限下放給子單位,是客戶自己的決定,不干我們的事。
這是同一條原則的第三次援引
系統設定那塊、弱點檢測那塊都做過同樣的判斷:落地版裝在客戶自己的機房,主機權限也都在他們手上,這類設定本來就該由客戶自己管。 硬要由我們鎖住,只會讓客戶完全不能自主。
這一條是第三次援引同一條原則。
| 能做的事 | 為什麼嚴重 |
|---|---|
| 用最上層那個身分對外寄信 | 而且會通過寄件人驗證——收件人的信箱不會標示可疑,因為那確實是該單位真正的郵件伺服器 |
| 對客戶或合作方發釣魚信 | 信來自真實網域,可信度極高 |
| 如果設定裡關掉了加密 | 密碼是完全明文送過去的 |
| 判斷依據 | 這件事 |
|---|---|
| 要先有帳號嗎 | 要,而且要有改寄信設定的權限 |
| 那個權限誰有 | 下層客戶的管理員就有(刻意下放的,共 9 個角色) |
| 要準備什麼 | 一台自己控制得了的主機,會收郵件連線即可——技術門檻很低 |
| 受害的是誰 | 最上層那個單位的對外信譽——被冒用的是它的名義,而不只是資料被讀走 |
| 影響範圍多大 | 縮在單一客戶內部——拿到的是同一家公司上層的帳密,不會跨到別家客戶去。這是評為中而不是高的原因 |
順帶一提:員工帳號目錄那支「測試連線」本來就是目標位址變了就不准沿用存的密碼、要求重填;寄信這支現在也補上同一行(CM-2111)。這不限制客戶任何權限,只是「你換了目標就自己重打密碼」。
問題:寄信失敗的處理程式,把整組郵件設定原封不動寫進系統紀錄檔——伺服器位址、寄件人、帳號、密碼、加密開關,整組都在裡面。
最值得注意的是觸發條件:這不需要攻擊者做任何事。密碼填錯一次、伺服器連不上一次、網路抖一下,就會寫進去。
同一支程式成功的時候是一欄一欄印的、不含密碼,只有失敗的時候把整組設定整包丟進去。而產品的「讀取郵件設定」功能本來就刻意把密碼遮掉了——遮了正門,後門卻開著。
共用地基修好的那道密碼遮蔽,蓋不到這裡
那道遮蔽只認得一種特定的寫法(欄位名與值都用雙引號包起來的那種格式);而這裡印出來的是另一種格式。
實際跑過:密碼一個字都沒有被遮掉,原封不動留在紀錄裡。
所以不能靠「上游已經修了」就放過這條,這一條單獨修了(CM-2111)。
修法(已修,CM-2111):錯誤訊息只印錯誤本身(連不上、被拒絕、逾時),不再把整組設定丟進去。
問題:連郵件伺服器時「有加密但沒認人」。對方拿一張隨便自簽的證明過來,系統照單全收、不會拋出任何錯誤,下一行就把帳號密碼送過去。
影響比第 2 條更廣:除了洩漏郵件帳密,每一封信的內容都會落到攔截者手上——包含登入用的一次性驗證碼與新帳號的初始密碼信。等於帳號被接管的材料整批送出去。
成因與另外兩處不同,這個區別在稽核場合很重要
「加密但不認人」在這個產品裡有三處,但成因分成兩種:
| 位置 | 成因 | 現況 |
|---|---|---|
| 員工帳號目錄 | 程式裡明確寫了「關掉驗證」那一行 | ✅ 已修(設定頁有憑證欄位) |
| 快取服務 | 同上,明確寫了關閉 | ✅ 已修(主系統那份複製品刪除,統一用套件修好的那份,CM-2043) |
| 寄信(本條) | 沒有關掉任何東西——那行呼叫是空的、什麼都沒帶,是程式語言內建的預設本來就不驗對方身分 | ✅ 已修(本條,CM-2111) |
不是我們關掉的,是我們沒有主動打開。 後果一樣(帳密與每一封信的內容都會被攔走),但成因不同。
為什麼這個區別要講清楚:稽核方會問「為什麼你們把驗證關掉」,而正確答案是「我們沒有關,是程式語言的預設如此、我們沒有額外加強」。這兩句在稽核場合的份量差很多。
修法:選了加密就驗證對方身分;既有設定升級後行為不變。
真正的問題是設定上寫了加密、程式卻沒有兌現驗證。客戶在設定頁選了加密,他合理相信連線是安全的——實際上半路有人假冒伺服器,系統照樣把帳密和信件交出去。設定騙了他。
現在的做法:
用內部郵件轉送的客戶不受影響——他們選「無加密」本來就可以,內網直送很常見。
與第 2 條在同一張工單修好(CM-2111,同一支檔案、同一段程式,分開改會互相踩到)。
問題:那個按鈕填什麼網址就打什麼,系統不限制目標。可以拿它去探測客戶內網有哪些機器、哪些服務開著。
誰按得動:它比「寄測試信」更嚴——要有通知設定的權限,還要是帳號層的最高管理員,兩個條件都滿足才按得下去。
還有一個權限更低的變體:把內網位址存起來,之後每次系統發通知都會去打它一次。
為什麼只評為低:回應的內容不會回傳給操作者,所以偷不到資料,只能探測。覆核者因此把提報的中風險降為低。
與第 1 條不是同一個病,不能共用一套修法
Discord 那個網址本身就是祕密——拿到就能冒名在那個群組發文,所以它留空時用存的那一組、呼叫端改不了目標。
兩條可以併成一張卡做(程式位置相鄰),但修法不同、不可共用一套。
建議修法(兩層一起做,尚未排入):
| 做什麼 | 擋的是什麼 | |
|---|---|---|
| ① | 擋掉指向內網的位址 | 攻擊者原本辦不到的事——他在外面碰不到客戶內網,借我們的伺服器是唯一的路 |
| ② | 只允許已知的通知服務網域(Discord 那支就只能打 Discord) | 拿我們當跳板打外網——避免我們的位址被列入黑名單,或在別人的紀錄上留下我們的名字 |
②比①更單純:不用維護「哪些算內網」的清單,直接比對「是不是 Discord 的網址」就好。
設定畫面完全不動,客戶照樣只填一個網址,擋在系統內部、使用者看不到。
寄信功能的資料格式裡宣告了「副本收件人」「密件副本」「附件」三個欄位,但實際寄信的程式完全沒有讀它們——填了就是丟掉,沒有任何警告或錯誤。
為什麼值得記:開發者看到有「副本」欄位,合理地以為填了就會寄副本,填完測試也不會報錯,但收件人永遠收不到,而且沒有任何線索指向原因。在稽核的情境下,這可能造成「以為通知了某個關係人、實際上沒有」。
不是資安問題,但確實是程式錯誤。
一句話:這塊的四條發現,三條指向同一件東西——系統存著的那組寄信帳號密碼,三條都已處理。一條是主動送給別人(第 1 條),兩條是被動洩漏(寫進紀錄、連線被攔)。
第 1 條屬於客戶自己的權限治理,不是產品缺陷:寄信設定全系統只有一份、存在最上層,改它的權限下放到各個下層客戶——這是刻意設計。要不要把這個權限下放給子單位,由客戶最上游的帳號自己決定。落地安裝版裝好時那一頁是空的,帳密由客戶自己填。
第 2、3 條已修好(CM-2111,同一支檔案一起改):寄信失敗只記位址與錯誤類別,選了加密就驗證對方身分。還沒修的是第 4 條(Discord 測試可當內網探測器,低)——原工單已隨 09-21 統一派工作廢,目前沒有修正卡,待決策者裁定是否排入。
一個橫跨產品的觀察:「加密但不認人」在這個產品裡是第三處,但寄信這處的成因與前兩處不同——前兩處是程式裡明確寫了關閉,這處是沒有主動打開。所以往後的程式審查要把「有沒有主動要求驗證對方身分」列為固定檢查項目;只查「有沒有人寫了關閉」會整類漏掉。
| 統計 | |
|---|---|
| 檢視輪數 | 2 輪、48 個檔案 |
| 通過的發現 | 8 條——寄信通知本身 4 條,另外 4 條是檢視時順手做密碼掃描撈到的、與這塊無關 |
| 最嚴重(🔴) | 0 條 |
| 高風險(🟠) | 1 條——版控裡的四把對外 AI 服務金鑰(已撤銷換發) |
| 已修 | 6 條——寄信通知本身第 2、3 條;順手撈到的那四條(外流的金鑰與密碼全部撤銷換發、版控殘留已清) |
| 裁定不修 | 1 條——第 1 條(權限面由客戶自行管控;程式面已加強換主機要重填密碼) |
| 未修 | 1 條——第 4 條(Discord 測試可探測內網,目前沒有修正卡) |