Guidant AI 資安檢視 · 模組報告
讓使用者用講的就生出報表的功能。檢視時查到任何一個最基層的員工,只要打字說「列出所有角色」「列出所有客戶」,就能拿到整份組織架構與權限配置——走正常畫面要權限,走這條路完全不用。這塊功能本身的五條問題全部已修好,順手撈到的兩條外流憑證也已撤銷換發。
使用者在畫面上用自然語言打字問問題(例如「列出所有專案的進度」),AI 自己決定要去呼叫系統裡的哪一支查詢功能,把查到的資料拿去設計版面、做成圖表顯示出來。
可以被 AI 呼叫的查詢功能,目前有 26 支——查使用者、查角色、查客戶、查部門、查專案、查公告、查流程進度等等。
AI 自己決定要呼叫哪一支查詢,所以「這個人能不能看這筆資料」必須在儀表板這一層把關——正常畫面入口上的權限檢查,這條路碰不到。
檢視時 26 支一支都沒有這道檢查;現在每一支都標明了需要什麼權限,沒標明的直接拒絕(第 2 條)。
檢視當時的一個陷阱:「列出所有使用者」會出錯,但那不是修好
檢視時「查使用者」那支會當場出錯,原因是儀表板自動補上的「客戶」條件那支認不得——是意外擋住,不是權限檢查;把那個條件補回去,這條路就會恢復暢通,而查角色、查客戶、查部門三支當時照樣打得通。現在真正的擋法是第 2 條的權限申報,不再靠這個意外。
檢視期間:2026-09-10(單日完成兩輪)|範圍:52 個檔案(主系統接線 18、模組本體 34)|共 2 輪
原始技術報告放在需求中心的 FR-083 站,檔名見下表最後一欄。那裡有每一輪的完整技術細節、檔案清單與逐條推理,供需要深究或稽核抽查時查閱。
| 輪次 | 查什麼 | 檔數 | 覆核投票 | 結果 | 原始報告檔名 |
|---|---|---|---|---|---|
| D2 | 主系統這端怎麼把 26 支查詢掛上去、那 26 支有沒有檢查權限 | 18 | 33 票全投完,零漏投 | 通過 11 條(這塊功能本身 3 條,另 8 條是順手撈到的密碼外洩) | scan-D2-host-wiring |
| D1 | 模組本身——AI 是怎麼決定要查哪一支的 | 34 | 6 票全投完,零漏投,無任何降級 | 通過 2 條;這輪只花 25 分鐘,是整批檢視裡最快的一輪 | scan-D1-package-core |
兩輪要合起來看,才是完整的一條路
單看任何一輪都看不出全貌:
前者是「門沒鎖」,後者是「而且任何人都走得到門口」。兩件事湊在一起才叫可以利用。
工具沒查、統籌者補查出來的三件事
工具兩輪都沒碰這三項,其中一項還會讓問題被講得比實際更嚴重:
另一項沒查的:那 26 支功能各自的內部
這兩輪證明的是「這條路徑上沒有權限檢查」。至於每一支功能自己內部有沒有別的防護,只有其中 7 支實際進去看過(成員相關那 7 支,確認內部也一樣不判權限)。
其餘 19 支沒有逐支進去看,不能當成乾淨。
排序按風險,同風險的同一類排在一起。「出事會怎樣」那欄講的是業務影響——誰受影響、損失什麼,不是技術現象。
| # | 問題 | 風險 | 分類 | 出事會怎樣(誰受影響) | 怎麼修 | 狀態 |
|---|---|---|---|---|---|---|
| 1 | 打字就能誘導 AI 選中 26 支查詢功能裡的任何一支,而且可以無限次重試 | 🟠 高 | 外部送什麼就收什麼 | 公司裡任何一個有帳號的人,都能拿到他本來看不到的東西——整份組織架構、誰有什麼權限、公司有哪些客戶、所有專案。而且每試一次不用付代價,可以反覆改寫問法直到成功 | 補上呼叫外部 AI 的等待逾時、每人每分鐘次數上限(與 AI 聊天助手那塊合併一起做);能拿到什麼則由第 2 條的權限檢查收口。實際做法:外部 AI 呼叫加 60 秒逾時、生成端點每人每分鐘 3 次上限(超過回 429) | ✅ 已修(工單 CM-2064,套件 commit 248132ec) |
| 2 | 那 26 支查詢完全不檢查「你能不能看這筆資料」 | 🟡 中 | 只驗登入、不檢查歸屬 | 拿得到整份組織架構與權限配置(誰在哪個部門、誰的權限最大、公司有哪些客戶)。這是對內釣魚與挑選攻擊目標的起點;同一份資料走正常畫面是要權限的 | 在儀表板呼叫查詢之前補一道檢查:每支查詢多標明「用這支要什麼權限」,沒標明的直接拒絕 | ✅ 已修(工單 CM-2038,commit 8f94e249d)26 支全部申報所需權限,沒申報的直接拒絕 |
| 3 | 專案清單有一道「視同管理員」的後門 | 🟡 中 | 只驗登入、不檢查歸屬 | 不是專案成員的人,也能列出該客戶底下全部專案。稽核專案的清單本身就是敏感資訊(哪家客戶正在被查什麼) | 已裁定:儀表板只能看到自己參與的專案,那道後門拿掉。與第 2 條同一套修法、同一個位置 | ✅ 已修(工單 CM-2038,commit 8f94e249d) |
| 4 | 查到的資料整包原樣送回畫面,夾帶密碼加密用的鹽值與「是不是超級管理員」旗標 | 🟡 中 | 回應夾帶不該送的欄位 | 畫面上只顯示三欄,但系統那一邊其實已經把整包送出去了——包含每個帳號的密碼加密材料。而且送給外部 AI 的樣本資料同樣沒有遮蔽 | 兩步:先把鹽值與超管旗標加進既有的「不要送」清單止血,再改成在資料本身打記號、看到記號就跳過。實際做法:共用序列化工具的不送名單加入密碼加鹽值、超級管理員旗標與各類 token 欄位;log 側由 FR-114.9-Z 收:身分套件查詢時的記錄只寫筆數,不再把整筆帳號資料(含密碼雜湊、鹽值、超管旗標)寫進 log | ✅ 已修(工單 CM-2064,套件 commit 248132ec;log 側 CM-2269) |
| 7 | 生成儀表板的功能只檢查有沒有買這個模組,不檢查使用者的角色有沒有「AI 儀表板」這項功能權限 | ⚪ 低 | 只驗登入、不檢查歸屬 | 客戶管理員刻意沒開給某些角色(例如稽核人員),那些人選單上看不到,直接打網址照樣能用;而且每用一次都要付兩次 AI 服務費——客戶的權限設定形同虛設,費用由原廠吸收。已實測 | 生成功能補上「AI 儀表板」功能權限檢查;要一起發新版的 AI 儀表板模組 | ✅ 已修,1.21.0 出貨(8-J,CM-2220,commit 80dedfbb5/套件 fb271590)。主系統掃描查出;搬進模組之前主系統原本的入口就有同樣問題 |
這八條跟 AI 儀表板沒有關係——是檢視時順手做的密碼掃描撈到的。列在這裡是為了完整,詳細歸在它們各自所屬的地方。
其中兩條是這一輪才發現的新問題,兩條都已撤銷換發:
| # | 問題 | 風險 | 分類 | 出事會怎樣(誰受影響) | 怎麼修 | 狀態 |
|---|---|---|---|---|---|---|
| 5 | 外部程式碼平台的存取通行證寫在版控文件裡,共四把 | 🟠 高 | 密碼外流 | 可用我們公司的身分讀寫該平台上的專案與問題單。拿得到程式庫歷史的人(含離職者、外包)撈得出來 | 到該平台後台撤銷,並查稽核紀錄 | ✅ 已修正(四把全數撤銷;版控殘留字串已由 CM-2048 清除,commit e8e134a4e) |
| 6 | 公司內部套件倉庫的管理員帳密 + 檔案儲存服務的金鑰 + 一組畫面登入帳密,寫在同一份交接文件裡 | 🟡 中 | 密碼外流 | 套件倉庫這把是整條供應鏈的根——有發布權的人可以推一個帶後門的元件上去,下次打包就自動裝進客戶手上的程式。檔案儲存那把則讀寫得了稽核證據。三樣都是內網環境的東西,外人拿到用不上,所以評為中 | 換發三樣帳密、清出版控 | ✅ 已修正(三樣已換發,舊值失效;交接文件裡的殘留字串已由 CM-2048 清除,commit e8e134a4e) |
其餘 6 條與先前已記錄的重複(客戶展示環境的資料庫密碼、四家 AI 服務的金鑰、雲端硬碟串接密鑰、安裝程式的原廠管理員密碼等),不重複列出。
下面只展開需要你自己判斷、或容易被誤解的幾條。 其餘的修法明確,看上面表格的「怎麼修」那一欄就夠了——沒有展開不代表沒查,也不代表不重要。
使用者打的字,跟「AI 可以選用哪些功能」的清單,被串成同一段純文字一起送給 AI,中間沒有任何區隔。
打個比方:這就像把「客人的點餐內容」跟「廚房的完整菜單與操作手冊」印在同一張紙上交給廚師——客人只要在自己那段字裡寫得夠像指令,廚師分不出哪句是點餐、哪句是手冊。
攻擊者可以反覆改寫措辭,直到 AI 穩定選中他想要的那一支。修正前改寫不需要付任何代價,因為沒有次數限制。
| 拿得到 | 為什麼敏感 |
|---|---|
| 角色與權限設定 | 知道誰的權限最大,可以挑目標 |
| 客戶與部門的完整架構 | 組織全貌,誰在哪裡一清二楚 |
| 所有稽核專案的清單 | 哪家客戶正在被查什麼,本身就是商業敏感資訊 |
| 公告(含還沒發布的草稿) | 而且內容前三筆會被原文送到外部 AI 服務 |
| 全公司的帳號名冊 | 登入帳號、信箱、所屬客戶與部門——對內釣魚的起點。這一支檢視時會出錯撈不到,原因見上方說明,但那是意外不是防護 |
| 判斷依據 | 這件事 |
|---|---|
| 要先有帳號嗎 | 要,必須是有效的登入帳號(所以不是最嚴重等級) |
| 需要什麼特殊權限嗎 | 不需要,最基層的員工就可以 |
| 能叫出系統裡任何程式嗎 | 不能——系統確實會檢查名字在不在那 26 支的名冊上,名冊外的叫不出來 |
| 攻擊要試幾次 | 想試幾次都可以,沒有次數限制、每次只花公司的 AI 額度 |
這塊補了兩樣(CM-2064):呼叫外部 AI 時的等待逾時(60 秒),以及每人每分鐘的次數上限(3 次,超過回「請求太頻繁」)。長度上限沿用既有的 2000 字限制。
🔴 這塊比 AI 聊天助手更急:那邊一次請求呼叫一次 AI,這邊一次請求呼叫兩次(先問 AI 要查什麼、再問 AI 怎麼畫)。同樣一個人、同樣的力氣,在這裡把系統拖垮或把 AI 額度燒光的成本只要一半。
兩塊的修法相同,合併在同一次改動裡做完。
至於「誰能查什麼」那道檢查,是第 2 條的事——兩條都已做完,這條路已經堵住。
程式分成兩層:「入口」負責檢查權限,「做事的那段」負責撈資料。使用者走正常畫面時,是先過入口、檢查通過了才往下走到做事的那段。
AI 儀表板不走入口,直接叫做事的那段。 所以那道檢查根本沒有被碰到——不是檢查失效,是這條路不經過檢查。
比喻:大樓門口有警衛檢查識別證,但有一條通道直接通到辦公室、不經過門口。警衛沒有失職,是有一條路不經過警衛。
最能說明問題的是這個對照——同一支查角色與權限的程式,兩條路:
| 走正常畫面 | 走 AI 儀表板 |
|---|---|
| 先檢查「你有沒有查看角色的權限」 | 沒有任何檢查 |
產品明確定義了「查看使用者」「查看角色」「查看客戶」「查看部門」這四個權限。走正常畫面時這四道檢查都在;走 AI 儀表板這條路,四個全部沒有作用。
儀表板本身有一份「可以查什麼」的清單(那 26 支)。每一支上面已經寫了它要什麼條件、會回什麼資料——只要多寫一欄「這支需要什麼權限」,儀表板在呼叫之前先檢查那一欄就好。
為什麼這樣最好:
| 理由 | 說明 |
|---|---|
| 一處補、26 支全涵蓋 | 檢查寫在呼叫前的那一個位置,不必逐支去改 |
| 做事的那段完全不動 | 正常畫面的行為一點都不受影響,不會改出新問題 |
| 以後不會再漏 | 新增查詢時天然就要填那一欄,忘了填會被擋下來 |
被排除的兩個做法:
| 排除的做法 | 為什麼不選 |
|---|---|
| 改那 26 支查詢本身,每支自己檢查 | 走正常畫面的人會被檢查兩次;而且 26 支要各改一次,以後新增的還是會漏 |
| 讓 AI 改走正常畫面的入口 | 等於把整個儀表板重寫一遍,代價與風險都太大 |
還有一條不能省的:沒有標明權限的查詢要直接拒絕,不能預設放行。如果寫成「有標示就檢查、沒標示就過」,日後有人新增一支忘了標,它會悄悄變成不檢查,不會有任何錯誤訊息。
問題:AI 儀表板查專案清單時,系統會把呼叫者當成管理員處理,繞過「你只看得到你參與的專案」這道限制。
🔴 這是刻意設計、不是寫錯——程式旁邊的說明文字自己寫明,這是為了讓舊版儀表板能看到整個客戶底下的全部專案而特地開的,客戶之間的隔離交給資料庫那一層負責。這不是疏忽,是一個在當時成立的決定。
AI 儀表板的定位是「人人可用的查詢工具」,所以它只能看到你自己參與的專案。 那個舊決定在「使用者用自然語言打字、AI 自己決定要查什麼」這個新情境下不再成立。
修法與第 2 條是同一套、同一個位置,只是它檢查的不是「你有沒有權限」,而是「你是不是這個專案的人」。兩條已在同一次改動裡做完。
一個要先講明白的後果:現在管理者也只看得到自己參與的專案。如果實際運作上管理者需要看全局,正確的做法是另外給他一個管理者專用的視圖,而不是讓所有人都看得到全部。這件事現在不用決定,等有人反映再處理。
形狀與設備清冊那塊的第 1 條相同(都是當初刻意放寬、現在重新確認),兩處的裁定方向一致。
問題:查到的資料被整包原樣攤平放進回覆內容裡,裡面含每個帳號的密碼加密用鹽值與**「是不是超級管理員」旗標**。
最容易誤會的一點:AI 設計的欄位清單只決定畫面上顯示哪幾欄標題,不決定系統實際送出哪些欄位。畫面上只顯示三欄,不代表送出去的只有三欄。
送去給外部 AI 服務的樣本資料(前三筆)同樣沒有做遮蔽。
檢視當時使用者資料那一支會出錯、撈不出來,鹽值暫時洩不出去;但擋住它的是上面說的那個意外,所以這條照樣修了。
| 步驟 | 做什麼 | 為什麼 |
|---|---|---|
| **第一步(已做) | 把資料轉成回覆內容的那支共用工具有一份「這些不要送」的清單,已加入密碼與鹽值、超級管理員旗標、各類通行證欄位** | 成本極低、立即止血 |
| **第二步(長期改善,未排) | 改成在資料本身打記號**,工具看到記號就跳過,不靠名字比對 | 才是真正治本 |
🔴 兩步的差別一定要看懂:
所以第一步是止血、不是終點。 一個機制出錯時的方向,比它平常對不對更重要。
⚠️ 另一個做法已被排除:「明列只送哪幾欄」聽起來更安全,但 AI 會從 26 支查詢裡自己挑一支,每支回來的資料長得都不一樣——等於要維護 26 份清單,漏一次就白做。
第 6 條的交接文件,與公告那塊報告裡提到的是同一份、同一行。裡面有三樣東西,全部明文寫在正文裡:
| 是什麼 | 拿到能做什麼 |
|---|---|
| 公司內部套件倉庫的管理員帳密 | 推一個帶後門的元件上去,下次打包就裝進客戶手上的程式 |
| 檔案儲存服務的金鑰 | 讀寫得了存放的稽核證據 |
| 一組畫面登入帳密 | 直接登入系統 |
🔴 同一組密碼散在至少五個地方:這份交接文件、打包腳本,以及畫面那邊的三支設定檔。
🔴 清理時最容易犯的錯:只清打包腳本與畫面那四個檔,交接文件這份還留著,等於沒清乾淨。三樣帳密現在都已換發,交接文件裡的殘留已由 CM-2048 一併清除。
還有一個容易混淆的分界要講清楚:
| 哪一件事 | 是什麼問題 | 怎麼修 |
|---|---|---|
| 意見回饋那塊講的「連套件倉庫沒有加密」 | 傳輸問題——連過去的時候沒加密,路上會被看到 | 改用加密連線 |
| 這一條 | 外流問題——帳密直接寫進版控裡了 | 換密碼、清出版控 |
兩件事相鄰但不同,修法也不同,不要併在一起處理——併了會只修一半。
一句話:檢視時這塊的問題集中在同一件事上——「誰能查什麼」這道檢查,在這條路徑上根本不存在,26 支一支都沒做。這塊功能本身的五條問題現在全部已修好:26 支查詢都申報了所需權限、沒申報的直接拒絕(第 2、3 條);鹽值與超管旗標不再送出(第 4 條);逾時與次數上限與 AI 聊天助手同一次補上(第 1 條);生成功能補上功能權限檢查(第 7 條)。順手撈到的兩條外流憑證(第 5、6 條)也已撤銷換發。
還留著的長期改善:第 4 條的第二步(在資料本身打記號、不靠名單比對)沒有排入,目前靠名單擋。
這塊的體質其實不錯——模組本身的名冊唯讀不可竄改、重複登記會當場報錯、少了守門設定會拒絕啟動(是檢視過的模組裡做得最好的一支)。問題不在寫得好不好,在於「誰能查什麼」這件事從一開始就沒有被納入設計。
不能宣稱的事:那 26 支功能各自內部有沒有別的防護,只有 7 支實際進去看過。
| 統計 | |
|---|---|
| 檢視輪數 | 2 輪、52 個檔案 |
| 通過的發現 | 13 條——4 條是這塊功能本身的問題,另外 8 條是檢視時順手做密碼掃描撈到的(與這塊無關),還有 1 條與前面重複 |
| 最嚴重 | 0 條 |
| 高風險 | 2 條——一條是 AI 可以被誘導去查不該查的資料,一條是外部平台的通行證外流,兩條都已修 |
| 已修 | 7 條(功能本身 4 條+主系統掃描另查出的第 7 條+外流憑證 2 條) |
| 未修 | 0 條 |