Guidant AI 資安檢視 · 模組報告

寄信與通知(jedi-notification)

系統對外講話的嘴巴——寄稽核提醒信、推 Discord 與 Telegram 訊息。最受關注的一條是「寄測試信」那個按鈕:寄信設定全系統只有一份、存在最上層,而「改寄信設定」的權限下放到各個下層客戶,所以下層的管理員可以按一下,把上層那組郵件帳密導到自己的機器上。

§1

這塊在產品裡做什麼

系統要通知人的時候——寄稽核提醒信、把流程事件推到聊天群組——走的都是這塊。它管三條通知管道:

管道 需要保管什麼機密
寄信 郵件伺服器位址 + 帳號 + 密碼
Discord 群組 一組專屬網址(誰拿到誰就能以我們的名義在那個群組發文)
Telegram 機器人通行證(拿到即可冒充那隻機器人)

它平常在做什麼

  1. 客戶在設定頁填好通知管道的帳密
  2. 系統把帳密存起來
  3. 要通知人時,主動對外連線把訊息送出去

為什麼它是敏感目標

三條管道有同一個共同點:都要保管客戶填的機密,都要主動對外連線。

保管機密 → 有「機密怎麼被讀出來」的風險。 主動連外 → 有「被騙去連到別的地方」的風險。


§2

檢視軌跡

檢視期間: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. 背景寄信時會不會讀到別家客戶的郵件設定——完全空白。若真的會讀錯,後果是「用 A 客戶的郵件伺服器寄 B 客戶的信」,屬於跨客戶外洩。
  2. Telegram 的機器人通行證拼在網址裡——網址會進系統紀錄檔與中間的網路設備紀錄,外洩面比放在其他位置大。這一輪沒有追這條。
  3. 那四條順手撈到的密碼外洩,不代表文件目錄與腳本目錄被檢查過——那兩處從來就不是檢視目標。

§3

問題一覽

排序按風險,同風險的同一類排在一起。「出事會怎樣」那欄講的是業務影響——誰受影響、損失什麼,不是技術現象。

# 問題 風險 分類 出事會怎樣(誰受影響) 怎麼修 狀態
1 「寄測試信」會把系統存著的那組郵件密碼,送到按鈕操作者自己填的那台主機 🟡 中 密碼外流 寄信設定全系統只有一份、存在最上層;而「改寄信設定」這個權限下放到各個下層客戶,所以下層的管理員可以把上層那組郵件帳密導到自己的機器上。拿到之後能用那個身分對外寄信,而且會通過寄件人驗證——收件人完全看不出是偽造的。在我們自己營運的多租戶環境裡,上層就是我們公司;落地安裝版裝好時這一頁是空的、帳密由客戶自己填,外流的是客戶自己那組 由客戶自行管控——寄信設定屬最上游帳號的權責,要不要把這個權限下放給子單位是客戶自己的決定。程式面可順手加強一項:測試連線時目標主機換了,就不沿用存著的密碼、要求重填 ✅ 程式面加強已做——伺服器位址或連接埠跟存著的不一樣時,不沿用存著的密碼、要求重新輸入(CM-2111)。權限面由客戶自行決定。
評為中風險的理由:外流的是同一家公司內部上層的帳密,範圍縮在單一客戶內部,與其他「同一家公司內部越權」的條目同一個量級
2 寄信失敗時,把整組郵件設定原樣寫進系統紀錄檔——那組設定裡有密碼 🟡 中 敏感內容寫進日誌 看得到系統紀錄的人就等於拿到密碼——維運人員、能查資料庫的人、外部紀錄收集服務的管理員,這些人遠多於被授權改郵件設定的人。而且不需要攻擊者做任何事,寄信失敗一次就會發生(密碼填錯、網路抖動都算)。⚠️ 共用地基那道密碼遮蔽蓋不到這裡,實跑驗過,密碼一個字都沒被遮掉 錯誤訊息只印錯誤本身,不要把整組設定丟進去 ✅ 已修——失敗紀錄只記伺服器位址、連接埠與錯誤類別(CM-2111)。主系統掃描又從系統診斷包那一端撞到同一件事(總表第 207 項),不另列;它暴露的那種密碼寫法已併進診斷包遮罩那張卡一起修好(8-B,CM-2212,1.21.0 出貨)
3 連郵件伺服器時「有加密但沒認人」——對方拿一張隨便自簽的證明來,系統照單全收 🟡 中 密碼外流 除了同樣洩漏郵件帳密之外,每一封信的內容都會落到攔截者手上——包含登入用的一次性驗證碼與新帳號的初始密碼信。等於帳號被接管的材料整批送出去。這條要成立,攻擊者得先在我們與郵件伺服器之間的網路路徑上(郵件服務在外部雲端時比較容易做到) 設定頁加「驗證伺服器憑證」開關與信任憑證欄位;新建設定預設要驗 ✅ 已修——新建/重存的設定預設驗證;升級前的既有設定維持不驗,設定頁頂部提示建議開啟(CM-2111)
4 「測試 Discord 群組」填什麼網址就打什麼,系統不限制目標 ⚪ 低 外部送什麼就收什麼 拿我們的伺服器當跳板去探測客戶內網——哪台機器活著、哪個服務開著。按得動的人比「寄測試信」更少:要有通知設定的權限,還要是帳號層的最高管理員。因為回應內容不會送回給操作者,所以偷不到資料、只能探測,風險因此評為低 兩層一起做:① 擋掉指向內網的位址;② 只允許已知的通知服務網域(Discord 那支就只能打 Discord)。設定畫面完全不動 ⬜ 未修(併入工單 CM-1605)

檢視時順手做密碼掃描撈到的四條

這四條跟寄信通知沒有關係——是檢視時順手做的密碼掃描撈到的。列在這裡是為了完整。

# 問題 風險 分類 出事會怎樣(誰受影響) 怎麼修 狀態
5 一個測試用設定檔被推上版控,裡面是四把真的對外 AI 服務金鑰 🟠 高 密碼外流 直接的財務損失——任何拿得到程式庫的人都能用我們公司的帳號呼叫那些服務;其中一把還能讀走服務端存的執行紀錄,裡面例行含有客戶資料 撤銷重發、把檔案撤出版控 ✅ 已修正——金鑰已撤銷換發,版控殘留字串待清(工單 CM-1607)
6 同一個檔案裡還有三樣東西:簽發登入憑證的金鑰、資料庫密碼、檔案儲存服務的金鑰。三樣的嚴重度不同,分項如下 ⚪ 低
(三項同級,理由見下)
密碼外流 ① 簽發登入憑證的金鑰:拿到它就能自己偽造一張管理員身分的登入憑證,不需要密碼也不需要雙因子。
② 資料庫密碼、③ 檔案儲存服務的金鑰:拿到就能直接讀寫資料。
🔴 三樣都只影響我們自己的開發機——安裝程式每裝一套都會各自隨機產生新的一份,所以外流的這三樣不會跟著出貨到任何客戶。影響範圍從「每一套裝出去的都中」縮成「我們自己的開發環境」
同上 ✅ 已修正——三樣都已撤銷換發,版控殘留字串待清(工單 CM-1607)
7 一支產生文件的腳本,把客戶展示環境的完整資料庫連線資訊(含密碼)寫死在程式碼裡 🟡 中 密碼外流 可以直接連進客戶會看到的展示環境資料庫——那個環境依規定等同正式環境 改成從環境設定讀取 ✅ 已修正——該組密碼已換發,版控殘留字串待清(工單 CM-1608)
8 系統管理員帳號的密碼寫死在三支腳本裡,其中兩支寫成「環境變數沒設就用這個」——而那個「這個」就是真密碼 🟡 中 密碼外流 拿到程式庫就等於拿到一組可用的管理員帳密。變數忘了設時會靜默用真密碼,操作的人不會被告知 同上 ✅ 已修正——該組密碼已換發,版控殘留字串待清(工單 CM-1608)

這四條都與其他模組頁重疊,問題總表請只算一次

  • 第 5 條(四把 AI 服務金鑰)= 公告那塊第 9 條,同一批九個檔。
  • 第 6 條(簽發登入憑證的金鑰)= 公告那塊第 6 條,同一把,兩頁的評級一致(低)——安裝程式每裝一套都會各自隨機產生,外流的只是我們開發機那一份。
  • 第 7 條(腳本寫死展示機連線資訊)= 意見回饋那塊第 1 條同一組密碼——而且它是那 249 個檔裡唯一一支會被執行的腳本,其餘全是文件與對話紀錄。
  • 第 8 條(三支腳本寫死管理員密碼)= 公告那塊第 11 條,但那一頁只列到一支,這裡的三支才是完整範圍(兩支寫成「環境變數沒設就用這個」、一支直接寫死沒有逃生門),三支用的是同一組密碼。

所有外流的通行證、金鑰、密碼都已經撤銷或換發完畢,剩下的只有把字串本身從版控裡清乾淨這件事——性質是打掃,不是堵漏。


下面只展開需要你自己判斷、或容易被誤解的幾條。 其餘的修法明確,看上面表格的「怎麼修」那一欄就夠了——沒有展開不代表沒查,也不代表不重要。

§4

第 1 條:「寄測試信」把存著的郵件密碼送到操作者指定的主機

問題是什麼

郵件設定頁有一個「寄測試信」按鈕。使用者不改密碼欄位的時候,系統會從資料庫撈出存著的那組真密碼,配上使用者這次送過來的設定去試寄。

問題在於——伺服器位址那一欄也是使用者填的。

所以整件事變成:

使用者填一台自己控制的主機位址  →  密碼欄留空不改
                ↓
系統:「好,我用存著的真密碼去連你指定的那台機器」
                ↓
使用者在自己的機器上收到那組存著的郵件帳號密碼

外流的是誰的帳密

寄信設定全系統只有一份、存在最上層;而「改寄信設定」這個權限下放到各個下層客戶。所以下層的管理員,可以把上層那組郵件帳密導到自己的機器上。

外流的到底是誰的帳密,要看產品裝在哪裡:

產品裝在哪裡 最上層是誰 外流的是誰的帳密
我們自己營運的多租戶環境 我們公司 我們公司對外寄信的那一組
客戶自己機房的落地安裝版 客戶自己的總管理帳號 客戶自己填進去的那一組

落地安裝版裝好的時候,這一頁是空的。 出貨的初始資料只建立「改寄信設定」那四個權限與選單,一筆寄信設定的資料列都沒有——帳密全部由客戶自己填。

這是刻意的設計

持有「改寄信設定」這個權限的角色有 9 個,橫跨最上層與 7 個業務客戶;程式裡也寫明這個權限就是要下放給業務客戶的管理員。

裁定:寄信設定由客戶最上游的帳號自行管控,要不要把這個權限下放給子單位,是客戶自己的決定,不干我們的事。

這是同一條原則的第三次援引

系統設定那塊、弱點檢測那塊都做過同樣的判斷:落地版裝在客戶自己的機房,主機權限也都在他們手上,這類設定本來就該由客戶自己管。 硬要由我們鎖住,只會讓客戶完全不能自主。

這一條是第三次援引同一條原則。

拿到之後能做什麼

能做的事 為什麼嚴重
用最上層那個身分對外寄信 而且會通過寄件人驗證——收件人的信箱不會標示可疑,因為那確實是該單位真正的郵件伺服器
對客戶或合作方發釣魚信 信來自真實網域,可信度極高
如果設定裡關掉了加密 密碼是完全明文送過去的

為什麼評為中風險

判斷依據 這件事
要先有帳號嗎 要,而且要有改寄信設定的權限
那個權限誰有 下層客戶的管理員就有(刻意下放的,共 9 個角色)
要準備什麼 一台自己控制得了的主機,會收郵件連線即可——技術門檻很低
受害的是誰 最上層那個單位的對外信譽——被冒用的是它的名義,而不只是資料被讀走
影響範圍多大 縮在單一客戶內部——拿到的是同一家公司上層的帳密,不會跨到別家客戶去。這是評為中而不是高的原因

順帶一提:同一個程式庫裡已經有正確的做法——員工帳號目錄那支「測試連線」是目標位址變了就不准沿用存的密碼、要求重填。寄信這支漏了這一行。這不限制客戶任何權限,只是「你換了目標就自己重打密碼」。


§5

第 2~4 條:其餘三條

第 2 條:寄信失敗時把密碼寫進系統紀錄(中)

問題:寄信失敗的處理程式,把整組郵件設定原封不動寫進系統紀錄檔——伺服器位址、寄件人、帳號、密碼、加密開關,整組都在裡面。

最值得注意的是觸發條件:這不需要攻擊者做任何事。密碼填錯一次、伺服器連不上一次、網路抖一下,就會寫進去。

同一支程式成功的時候是一欄一欄印的、不含密碼,只有失敗的時候把整組設定整包丟進去。而產品的「讀取郵件設定」功能本來就刻意把密碼遮掉了——遮了正門,後門卻開著。

共用地基修好的那道密碼遮蔽,蓋不到這裡

那道遮蔽只認得一種特定的寫法(欄位名與值都用雙引號包起來的那種格式);而這裡印出來的是另一種格式。

實際跑過:密碼一個字都沒有被遮掉,原封不動留在紀錄裡。

所以不能靠「上游已經修了」就放過這條,這一條必須單獨修。

修法:錯誤訊息只印錯誤本身(連不上、被拒絕、逾時),不要把整組設定丟進去。

第 3 條:加密連線不驗對方身分(中)

問題:連郵件伺服器時「有加密但沒認人」。對方拿一張隨便自簽的證明過來,系統照單全收、不會拋出任何錯誤,下一行就把帳號密碼送過去。

影響比第 2 條更廣:除了洩漏郵件帳密,每一封信的內容都會落到攔截者手上——包含登入用的一次性驗證碼與新帳號的初始密碼信。等於帳號被接管的材料整批送出去。

成因與另外兩處不同,這個區別在稽核場合很重要

「加密但不認人」在這個產品裡有三處,但成因分成兩種:

位置 成因 現況
員工帳號目錄 程式裡明確寫了「關掉驗證」那一行 ✅ 已修(設定頁有憑證欄位)
快取服務 同上,明確寫了關閉 ⚠️ 套件那半修了,主系統自己那支還沒
寄信(本條) 沒有關掉任何東西——那行呼叫是空的、什麼都沒帶,是程式語言內建的預設本來就不驗對方身分 ❌ 完全沒碰

不是我們關掉的,是我們沒有主動打開。 後果一樣(帳密與每一封信的內容都會被攔走),但成因不同。

為什麼這個區別要講清楚:稽核方會問「為什麼你們把驗證關掉」,而正確答案是「我們沒有關,是程式語言的預設如此、我們沒有額外加強」。這兩句在稽核場合的份量差很多。

修法:選了加密就驗證對方身分;既有設定升級後行為不變。

真正的問題是設定上寫了加密、程式卻沒有兌現驗證。客戶在設定頁選了加密,他合理相信連線是安全的——實際上半路有人假冒伺服器,系統照樣把帳密和信件交出去。設定騙了他。

現在的做法:

  • 設定頁在加密開關下方多一個「驗證伺服器憑證」開關,新建的設定預設開著。
  • 接公司內部郵件伺服器(內部憑證或自簽)的客戶,把簽發它的 CA 憑證貼進「信任憑證」欄位即可驗過;填了就只信這一份。
  • 真的拿不到憑證的客戶可以關掉驗證,開關旁會寫明風險。
  • 升級前存的設定沒有這個開關的值,一律當作「不驗」——不這樣做,升級當天所有接自簽伺服器的客戶都會突然寄不出信。設定頁打開時頂部會提示「目前未驗證,建議開啟」,但不會替客戶自動改掉,要客戶自己存檔才生效。

用內部郵件轉送的客戶不受影響——他們選「無加密」本來就可以,內網直送很常見。

與第 2 條合成同一張工單(同一支檔案、同一段程式,分開改會互相踩到)。

第 4 條:「測試 Discord 群組」可當內網探測器(低)

問題:那個按鈕填什麼網址就打什麼,系統不限制目標。可以拿它去探測客戶內網有哪些機器、哪些服務開著。

誰按得動:它比「寄測試信」更嚴——要有通知設定的權限,還要是帳號層的最高管理員,兩個條件都滿足才按得下去。

還有一個權限更低的變體:把內網位址存起來,之後每次系統發通知都會去打它一次。

為什麼只評為低:回應的內容不會回傳給操作者,所以偷不到資料,只能探測。覆核者因此把提報的中風險降為低。

與第 1 條不是同一個病,不能共用一套修法

  • 第 1 條送出去的是系統存著的密碼(憑證外流)。
  • 第 4 條送出去的是呼叫者自己填的網址(只是被當跳板)。

Discord 那個網址本身就是祕密——拿到就能冒名在那個群組發文,所以它留空時用存的那一組、呼叫端改不了目標。

兩條可以併成一張卡做(程式位置相鄰),但修法不同、不可共用一套。

修法(兩層一起做):

做什麼 擋的是什麼
① 擋掉指向內網的位址 攻擊者原本辦不到的事——他在外面碰不到客戶內網,借我們的伺服器是唯一的路
② 只允許已知的通知服務網域(Discord 那支就只能打 Discord) 拿我們當跳板打外網——避免我們的位址被列入黑名單,或在別人的紀錄上留下我們的名字

②比①更單純:不用維護「哪些算內網」的清單,直接比對「是不是 Discord 的網址」就好。

設定畫面完全不動,客戶照樣只填一個網址,擋在系統內部、使用者看不到。


§6

順手記下的一件小事(不是資安問題)

寄信功能的資料格式裡宣告了「副本收件人」「密件副本」「附件」三個欄位,但實際寄信的程式完全沒有讀它們——填了就是丟掉,沒有任何警告或錯誤。

為什麼值得記:開發者看到有「副本」欄位,合理地以為填了就會寄副本,填完測試也不會報錯,但收件人永遠收不到,而且沒有任何線索指向原因。在稽核的情境下,這可能造成「以為通知了某個關係人、實際上沒有」。

不是資安問題,但確實是程式錯誤。


§7

這塊的結論

一句話:這塊的四條發現,三條指向同一件東西——系統存著的那組寄信帳號密碼。一條是主動送給別人(第 1 條),兩條是被動洩漏(寫進紀錄、連線被攔)。

第 1 條屬於客戶自己的權限治理,不是產品缺陷:寄信設定全系統只有一份、存在最上層,改它的權限下放到各個下層客戶——這是刻意設計。要不要把這個權限下放給子單位,由客戶最上游的帳號自己決定。落地安裝版裝好時那一頁是空的,帳密由客戶自己填。

真正要動程式的是第 2、3 條(合成一張工單,同一支檔案)與第 4 條(可與第 1 條併卡做,但修法不同)。其中第 2 條特別要注意:共用地基那道密碼遮蔽蓋不到它,不能當作已經被上游修掉了。

一個橫跨產品的觀察:「加密但不認人」在這個產品裡是第三處,但寄信這處的成因與前兩處不同——前兩處是程式裡明確寫了關閉,這處是沒有主動打開。所以往後的程式審查要把「有沒有主動要求驗證對方身分」列為固定檢查項目;只查「有沒有人寫了關閉」會整類漏掉。

統計
檢視輪數 2 輪、48 個檔案
通過的發現 8 條——寄信通知本身 4 條,另外 4 條是檢視時順手做密碼掃描撈到的、與這塊無關
最嚴重(🔴) 0 條
高風險(🟠) 1 條——版控裡的四把對外 AI 服務金鑰(已撤銷換發)
已修正 7 條——寄信通知本身第 1(程式面)~3 條;順手撈到的那四條,外流的金鑰與密碼全部撤銷換發完畢,剩版控殘留字串待清
待處理 寄信通知本身第 4 條(Discord 測試可探測內網,工單 CM-1605),加上殘留字串清理(工單 CM-1607、CM-1608)

你想知道 看哪裡
我們用什麼方法查、結果有多可信 檢視方法與工具
其他模組的檢視結果 回總報告首頁