FR-083 · 需求索引 · 本頁由 build 掃資料夾生成

FR-083 AI 儀表板(jedi-ai-dashboard)資安檢查

✅ 兩棒都掃完(2026-09-10)。D2(宿主接線 18 檔)11 條、D1(套件本體 34 檔)2 條,兩棒 stamp 皆 verified(33 票/6 票全投)。D1 已補完 27 支 API 權限形狀表,並查出 D2 未觸及的「沒有任何次數與花費限制」。發現已全數處理——對應總表 M15 七件全部已修,隨 1.21.0 出貨(早期修正卡 09-21 作廢,改照內化版問題總表派工)

狀態:✅ 已完成 文件 2 份

🔴 一頁看完

任何一個最基層的員工,只要對 AI 儀表板打字說「列出所有使用者」,就能拿到全公司的帳號名冊——而且回傳的資料裡還夾帶了每個帳號密碼加密用的「鹽值」。

同一個查詢功能,走正常的網頁路徑需要「使用者讀取」權限,走 AI 儀表板這條路完全不用。

兩棒掃完後,完整的圖像是這樣:D2 證明「27 支查詢功能沒有任何一支做權限檢查」,D1 證明「使用者確實能用打字誘導 AI 去選中其中任何一支,而且沒有次數限制可以一直重試」。兩半合起來才是完整的攻擊路徑。

§1

這在做什麼(白話)

「AI 儀表板」讓使用者用自然語言打字問問題(例如「列出所有專案的進度」),AI 自己決定要呼叫系統裡的哪一支查詢功能,把查到的資料拿去設計版面做成圖表。

可以被 AI 呼叫的查詢功能總共有 27 支,這個 arc 要回答的是:那 27 支有沒有檢查權限?查到的資料會不會被送到公司外面?使用者能不能用打字誘導 AI 去查他本來看不到的東西?

§2

為什麼掃它

上一個案子(FR-079)已經證明這條路有洞,但當時只驗證了 27 支裡的 1 支。

FR-079 的 F13 查到「AI 儀表板可以直接呼叫公告查詢,不經過網頁那層的任何權限檢查,而且結果前三筆原文送給第三方 AI」。這次是專門來查剩下那 26 支的。

§3

進度

棒 掃什麼 檔數 狀態 報告
D2 主專案的接線與 27 支查詢功能名冊 18 ✅ 已掃完並驗收(11 條) 報告
D1 套件本身(AI 怎麼決定要查什麼) 34 ✅ 已掃完(2 條,含 27 支形狀表) 報告
§4

D2 找到什麼

範圍內 3 條(都跟「繞過權限檢查」有關)

# 這是什麼問題 嚴重度
F3 任何登入者可透過 AI 儀表板列出全公司的帳號、角色、租戶、部門。產品自己定義了四個權限點(user.read/role.read/tenant.read/department.read),這條路四個全繞過 🟡 中
F9 回應夾帶每個帳號的密碼鹽值。正常的列表功能刻意排除了這個欄位,唯獨 AI 儀表板這條路沒做過濾 🟡 中
F10 專案清單有「當作管理員」後門,非成員可列舉租戶內全部專案。🔴 這是刻意設計不是寫錯(見報告) 🟡 中

最能說明問題的是這個對比(首腦已開檔核對):

同一個 UserService.get_users 方法,兩條路:

走正常網頁路徑                        走 AI 儀表板
user_route.py:80                      dashboard_apis/auth.py:31
  @capability_required("user.read")     (沒有任何權限檢查)

範圍外 8 條(密碼被寫進版控檔案,順手撿到的)

其中 2 條是新的、比較嚴重:

  • F1(🔴 高):GitLab 個人存取權杖寫在版控文件裡,綁著本專案的 CI 專案編號
  • F2(🔴 高):公司套件倉庫(Nexus)的管理員帳密 + 檔案儲存(MinIO)金鑰寫在交接文件裡

F2 值得特別注意:上一個案子查到「同一個套件倉庫走沒加密的連線」,現在又查到「管理員帳密外流」——同一個目標的兩個弱點,加起來比單看任何一個都嚴重。

其餘 6 條多與先前已記錄的重複(POC 資料庫密碼、四家 AI 金鑰、Google OAuth 密鑰、原廠管理員密碼等)。

§5

D1 找到什麼

# 這是什麼問題 嚴重度
F1 打字就能叫出 27 支查詢功能裡的任何一支。使用者打的字和「有哪些功能可以選」的清單被串成同一段文字送給 AI,中間沒有分隔——攻擊者可反覆改寫措辭直到 AI 選中目標 🔴 高
F2 查到的資料整包原封不動送回瀏覽器,夾帶密碼鹽值與「是不是超級管理員」旗標。送去給外部 AI 的 3 筆樣本同樣沒有脫敏 🟡 中

D1 與 D2 要合起來看才是完整的攻擊路徑:D2 說「那 27 支沒有各自的權限檢查」,D1 說「而使用者確實能誘導 AI 選中其中任何一支」。

兩個工具沒報、首腦人工查出來的重點:

  • 🔴 完全沒有次數與花費限制(已 grep 全套件零命中)。每試一次就真的打兩次 AI、花兩次錢——這是 F1 能反覆重試到成功的根本原因,兩件事要一起看
  • ⚠️ AI 呼叫沒有設 timeout。與 FR-082 同款:SDK 預設等 10 分鐘,而伺服器 120 秒就砍,而這一側一次請求打兩次 AI,風險更高
  • ✅ 一個重要的更正:系統確實有驗證 AI 回的名字在不在名冊內,攻擊者叫不出名冊以外的東西。這讓 F1 的嚴重度更精確——是「在 27 支裡誘導」,不是「可以叫出任何方法」。工具沒查這一步,不查的話會把問題講得比實際嚴重

套件本體體質其實不錯:名冊唯讀不可執行期竄改、重複申報會當場拋錯、缺守門會拒絕掛載(三支掃過的套件裡做得最好的一支)、開發用啟動殼零憑證、密鑰專項零命中。問題全部集中在「誰能查什麼」這一件事上。

§6

✅ 卡片點名的「27 支 API 權限形狀表」——D1 已補完

D2 當時工具只做了 5 支(auth 4 + project 1),其餘 22 支由 D1 補完,完整表在 D1 報告。

補完後的關鍵結論:這張表其實不必逐支查守門,因為守門根本不存在於這條路徑上——不是「有些有、有些沒有」,是一支都沒有。所以表要看的是**「哪支的資料最敏感」**,那就是修的優先順序:

auth 4 支(最高)→ participant 7 支+system_config 1 支(次高)→ project 2 支(要先做產品決策)→ 其餘。

participant 那 7 支首腦已開檔確認:service 方法本身也完全不判權限,而且正是「申報成 <strong>kwargs 所以租戶/部門過濾被默默丟掉」的那一類(FR-079 F13 的同款成因,該機制在這裡還活著**)。

§7

這次結果可信到什麼程度

「這 13 條是真的嗎」→ ✅ 可信。 兩棒 stamp 皆乾淨的 verified:D2 是 33 票全投(11 條×3)、D1 是 6 票全投(2 條×3),零漏投、零中斷。D2 檢查員主動降了兩條嚴重度。首腦兩棒都另開檔核對,全部屬實,且核對過程各修正了一處工具沒講的事(D2 的 F10「這是刻意設計」、D1 的「名字其實有驗證在名冊內」)。

「是不是只有這 13 條」→ ❌ 不可信。 兩棒都是快篩模式(low)。27 支 API 的權限形狀已由 D1 補完,但那 27 支各自的內部實作沒有逐支進去看——本 arc 證明的是「這條路徑完全不檢查權限」,至於每支功能內部有沒有別的防護,只有 participant 7 支實際確認過。D2 那 8 條範圍外的密碼外洩也不代表 docs/、scripts/ 被檢查過。

§8

修正卡

現況:全數已修,隨 1.21.0 出貨。 本 arc 發現已登記進跨 arc 總表 §3,後由 FR-114 修正線照 docs/security-report/ 問題總表(M15-1~7)修完,含 AI 儀表板 27 支查詢補權限、查詢結果過濾鹽值、生成功能補功能權限(CM-2220)、外流憑證撤銷換發。

§9

座標

  • 跨 arc 總表:../security-scan-consolidated/README.md(§3 有這三條的完整修法)
  • 直接相關的前案:FR-079 F13——本 arc 的起點
  • 同屬 AI 功能面:FR-082(AI 聊天機器人,共用同一把 AI 金鑰)
  • 首腦手冊:.claude/skills/security-scan-lead/SKILL.md
  • branch:BE repo 與 jedi monorepo 都在 feature/FR-075
§10

文件

以下全部由 build 掃資料夾產生,新增檔案重 build 即自動出現。標題連結指向渲染後的 HTML,md 連向源檔。

證據與盤點

文件 類型 標題 最後更新
scan-D1-package-core / md 盤點證據 D1 檢查結果:AI 儀表板套件本體(AI 怎麼決定要查什麼) 2026-09-10
scan-D2-host-wiring / md 盤點證據 D2 檢查結果:AI 儀表板的接線與 27 支查詢功能 2026-09-10
§11

Notion 卡

卡片內容(決策紀錄、驗收條件)以 Notion 為準,本頁只記座標。

關係 卡號 標題 狀態
母案 CM-1639 FR-083 AI 儀表板(jedi-ai-dashboard)資安掃描(兩棒,只掃不修) —
子卡 CM-1640 D2 宿主接線與 27 支 API 名冊(18 檔,BE repo) 修正待驗證
子卡 CM-1641 D1 套件本體(34 檔,jedi monorepo) 修正待驗證