FR-075 · 需求索引 · 本頁由 build 掃資料夾生成
✅ S1-S7 全部掃完並驗收;發現已全數處理——13 張修正卡全部已修(含 CRITICAL CM-1575),S5/S6 衍生的 CM-1585/1586/1588/1589 亦已修,隨 1.21.0 出貨(CM-1559 RLS fail-open 由 FR-094 CM-1788 改 fail-closed 收口)
這是六個資安掃描 arc 之一。 六個 arc 合起來的結論、修正卡狀態、還沒開卡的待辦與覆蓋率地圖,在跨 arc 總表:
security-scan-consolidated/——要問「總共掃出什麼、還有哪些要修」看那份,本頁只講這一支。
用 Claude Code 的 claude-security plugin 逐支掃描自家 jedi-* 套件,把掃出來的問題整理成清單, 再由決策者逐條裁決要不要修、修的優先序,然後開卡交 runner 執行。
掃描不等於修正——本 FR 的產出是「問題清單 + 裁決結果」,實際修正另外開卡。
jedi-* 套件是全產品的地基:jedi-iam 管登入與授權、jedi-common 管 DB session 與 RLS。 這兩支出問題等於整個產品出問題,而它們過去只被人工 review 過,沒做過系統性的安全掃描。
2026-07 那次資安掃描(docs/features/security-scan-2607/)掃的是主專案 BE 與 FE,沒有涵蓋 jedi-* 套件。
第一輪試掃(2026-09-05)不完整,已重做完成。 那一輪派了 40 個 agent 只有 28 個回報, 且驗證面板從未執行。找到 19 條問題、7 條 HIGH 經逐條開檔核對屬實, 但覆蓋率無法宣稱——被砍掉的 12 個 agent 對應哪些區塊沒有紀錄。那份清單是下限不是全貌。
重做的方式是把 jedi-iam 切成七塊、每塊獨立跑完整條含驗證面板。
切法是「按業務模組垂直切」:每一棒拿到一個模組從 route 到 service 到 domain 到 repository 的完整路徑。 第一版曾把 S4 到 S6 按 DDD 分層水平切(api 一塊、service 一塊、infra 一塊),決策者指出這樣研究員看不到 層與層的接縫,而權限漏洞恰恰活在接縫上——route 收了一個 id,要看到 service 才知道有沒有驗證那個 id 屬於呼叫者。那三張卡(CM-1550 到 1552)已作廢。
| 棒次 | 範圍 | 檔數 | 卡號 | 狀態 |
|---|---|---|---|---|
| S1 | 認證與外部身分綁定 | 11 | CM-1547 | ✅ 已完成(8 發現:5 HIGH/3 MEDIUM,verified) |
| S2 | 授權守門與提權路徑 | 8 | CM-1548 | ✅ 已完成(0 發現,verified) |
| S3 | 第二因子與人機驗證 | 34 | CM-1549 | ✅ 已完成(2 發現:1 HIGH/1 MEDIUM,verified) |
| S4 | 使用者本體與密碼變更 | 43 | CM-1553 | ✅ 已完成(5 發現:2 CRITICAL/1 HIGH/2 MEDIUM,面板全數 3/3,verified,無越界)(報告) |
| S5 | 角色與權限能力 | 49 | CM-1554 | ✅ 已完成(2 發現:2 MEDIUM,14 agent 全回報,verified;F1 3/3、F2 2/1,另 2 條重複候選被面板歸併)(報告) |
| S6 | 租戶與組織單位 | 47 | CM-1555 | ✅ 已完成(1 發現:1 MEDIUM,26 agent 全回報,8 候選投完 24 票,verified;F1 3/3 全票。另有 3 條真 bug 被面板判非資安,建議另開卡)(報告) |
| S7 | 登入態、UI 路由、middleware 與共用工具 | 74 | CM-1556 | ⚠️ 第 4 次跑完但研究員越界:9 條裡 8 條重複 S1(已各自開卡),唯一範圍內的 Redis TLS 已開 CM-1565;middleware/登入態/plugin 預設值等本棒核心讀過但零候選,不能算乾淨(報告) → ✅ 已改 1M、收窄範圍重跑並驗收(2026-09-10):4 條候選零越界、stamp verified,1 條 MEDIUM+人工 2 條 |
七棒合計 266 檔,覆蓋 jedi-iam 全部生產程式碼(只排除翻譯檔與 i18n script),各棒無重複。
S4~S7 首輪全滅的教訓(2026-09-06):四棒都超過 40 檔,研究員繼承 runner 的 Sonnet 5(200K), plugin 把研究員寫死 effort: xhigh 且要求追完每個 caller,讀到 20 幾萬 token 時每步思考變慢, 超過 workflow 的 180 秒無 tool call 即判 stalled 就被砍掉從零重派。S1~S3 是 8~34 檔沒踩線。 解法只改一件事:runner 主 session 切 Opus 5 (1M context),卡片、範圍、effort 全不動。 不切小範圍——S7 證明研究員為追脈絡一定往外讀,切小只會多一輪重複。細節見 scan-methodology.md。
jedi-common 後續另案掃描(FR-085 起)。
| 卡號 | 修什麼 | 來源 | 嚴重度 | 狀態 |
|---|---|---|---|---|
| CM-1557 | MFA 驗證碼無次數限制,加 per-user 失敗計數 5 次即鎖 | S3 F1,面板 3/3 | HIGH | ✅ 已修(jedi-iam b51b914) |
| CM-1558 | Turnstile 缺金鑰靜默 fail-open,改拋錯 | S3 F2,面板 2/3;FR-076 L1 越界第三次確認 | MEDIUM | ✅ 已修(jedi-iam 2bf2003) |
| CM-1559 | RLS fail-open:無 context/tenant_id 為 0 不再給 super admin,signed-token 改填真實租戶 | 首腦復核加開(工具未報) | MEDIUM,影響面最廣 | ✅ 已修(拆 CM-1787/1788,FR-094 CM-1788 無身分改 fail-closed;總表 M04-2) |
| CM-1560 | LDAP 登入三洞:OpenLDAP 兩段式 bind 驗密碼、filter escape、TLS 驗憑證 | S1 F1+F2+F6,面板 3/3 | HIGH | ✅ 已修(TLS 項退回重做一次) |
| CM-1561 | Google 登入殼:serializer 白名單+factory 拔除+綁定端同步(原裁拔除,後改裁關閉入口不拔除) | S1 F3+F5,面板 3/3 | HIGH | ✅ 已修(改裁關閉入口、程式碼保留不可啟用) |
| CM-1562 | 外部身分綁定加本人檢查 | S1 F4,面板 3/3 | HIGH | ✅ 已修 |
| CM-1563 | 密碼登入帳號枚舉:統一回 401 同碼+時間拉平 | S1 F7,面板 3/3 | MEDIUM | ✅ 已修 |
| CM-1564 | LDAP 連線測試外洩密碼:改位址時強制重輸 secret | S1 F8,面板 3/3 | MEDIUM | ✅ 已修 |
| CM-1565 | Redis TLS 寫死不驗憑證:ssl=True 時強制 cert_reqs=required | S7 F8/第一輪 M-7,面板 3/3 | MEDIUM | ✅ 已修(後以 CM-2043 收斂為單一份實作) |
| CM-1575 | 忘記密碼端點把重設憑證回傳給呼叫者:回固定空 body,第二出口一併檢視 | S4 F1+F2,面板各 3/3 | 🔴 CRITICAL,最優先 | ✅ 已修(jedi-iam a9edf1d) |
| CM-1576 | 自助 profile unknown=INCLUDE 可夾帶 user_roles 自我提權:改專屬 schema 白名單 |
S4 F3,面板 3/3,conf MEDIUM | HIGH,先實測 | ✅ 已修 |
| CM-1577 | update_user/add_user/批次匯入改密碼不驗強度:補 validate_password_policy(CM-683 修一半) | S4 F4,面板 3/3 | MEDIUM | ✅ 已修 |
| CM-1578 | Excel 上傳目錄用未驗證 login_name:格式驗證提升到 schema+目錄改用 uid | S4 F5/第一輪 M-10,面板 3/3 | MEDIUM | ✅ 已修 |
S4 的 CRITICAL 首腦親自追完整條路徑確認:route 免登入(設計正確)→ dump 的 schema 第一欄就是 uid → service 組信件連結用的正是同一個 uid → 重設端點只驗 token 不問身分。知道目標 email 即可接管任何帳號, 含原廠 admin。修好進版前建議 nginx 對 /forget-password 加 IP 節流當臨時緩解(環境異動,等令)。
CM-1559 的來由:S2 掃描 0 發現,但 signed_token.py 確實在範圍內。工具沒報是因為該檔 docstring 把 fail-open 寫成刻意設計,研究員讀到就接受了。而 jedi-common db.py 自己的註解記載了 tenant-102 帶 X-Tenant-ID: 0 看到整張 roles 表的實際案例。工具會被程式碼註解說服,看報告時要記得這個盲點。
S1 的 8 條併成 5 張(同檔同根因併卡)。第一輪的 M-6(未設加密時明文 bind)S1 沒重新找到, 首腦判定併入 CM-1560 順帶處理,不另開卡。
派工衝突:CM-1560/1561/1562 都動 ldap_adapter.py 或 user_auth_provider_service.py, 序列做不平行。CM-1557/1558/1563/1564 各自獨立可平行。CM-1559 影響面最廣單獨慢做。
換人或換帳號接手,讀 handoff/security-scan-STATE.md(現況)+ .claude/skills/security-scan-lead/SKILL.md(手冊)。FR-075 與 FR-076 共用這份 STATE。
scan-findings-batch1.md — 第一輪的 19 條發現。不完整、未經面板驗證, 但七條 HIGH 已逐條開檔核對,可當作重掃的對照基準scan-iam-1-auth-and-external-identity.md — S1 重掃結果:8 發現(5 HIGH/3 MEDIUM,面板全數 3/3 一致)、verified,含與第一輪 H-1~H-5/H-7、M-5、M-9 的對照分析scan-iam-2-authz.md — S2 重掃結果:0 發現、verified,含與第一輪 M-3 的對照分析scan-iam-3-mfa-turnstile.md — S3 重掃結果:2 發現(1 HIGH/1 MEDIUM)、verified,含與第一輪 H-6/M-4/L-1 的對照分析scan-iam-4-user-and-password.md — S4 掃描結果:5 發現(2 CRITICAL/1 HIGH/2 MEDIUM)、verified、17 agent 全回報 0 錯誤、面板全數 3/3、全部落在指派範圍內無越界;含全系列首見 CRITICAL(忘記密碼端點回傳重設憑證,知道 email 即可接管任何帳號含原廠 admin),並確認第一輪 M-10 路徑穿越scan-iam-5-role-and-capability.md — S5 掃描結果:2 發現(皆 MEDIUM)、verified、14 agent 全回報 0 錯誤;F1 角色讀取端點無守門(外洩租戶權限矩陣+成員名冊含 email/電話/職稱)、F2 權限守門採計已停用/軟刪除/過期/他租戶的角色指派(與 get_viewable_by_user_uid 的正確查法已分岔);本塊第一輪未涵蓋故無舊發現對照,兩條均為新發現scan-iam-6-tenant-org-unit.md — S6 掃描結果(1M 重跑):1 發現(MEDIUM)、verified、26 agent 全回報 0 錯誤、8 候選全投完票;F1 組織單位讀取端點無 department.read 守門(外洩整棵部門樹含 metadata/路徑/稽核帳號,與 S5 F1 同病灶建議合併修)。另有 3 條被面板判定「真 bug 但非資安」值得另開非資安卡:tenant/org-unit 部分更新清空 parent_id、org_unit 建立 created_user 寫成 NULL。文末附錄保留首輪 Sonnet 失敗記錄scan-iam-7-login-uiroute-common.md — S7 掃描結果:流程跑完但研究員讀檔越界,9 條面板確認發現裡 8 條是 S1 已知問題重複(對應修正卡 CM-1560~1564),只有 1 條 Redis TLS(M-7 對照)真正落在本棒範圍且尚未開卡;本棒真正獨有的 middleware/domain service/plugin.py 預設值等部分沒有任何候選,需另外收窄範圍重掃scan-methodology.md — 工具用法、effort 等級的成本差異、兩次失敗的教訓docs/features/security-scan-2607/ — 2026-07 主專案資安掃描,範圍不含 jedi-* 套件docs/claude/jedi-packages.md — jedi-* 套件名冊與 API 參考以下全部由 build 掃資料夾產生,新增檔案重 build 即自動出現。標題連結指向渲染後的 HTML,md 連向源檔。
| 文件 | 類型 | 標題 | 最後更新 |
|---|---|---|---|
| scan-findings-batch1 / md | 盤點證據 | 第一批掃描發現:jedi-common + jedi-iam | 2026-09-05 |
| scan-iam-1-auth-and-external-identity / md | 盤點證據 | S1 掃描結果:jedi-iam 認證與外部身分綁定 | 2026-09-05 |
| scan-iam-2-authz / md | 盤點證據 | S2 掃描結果:jedi-iam 授權守門與提權路徑 | 2026-09-05 |
| scan-iam-3-mfa-turnstile / md | 盤點證據 | S3 掃描發現:jedi-iam 第二因子與人機驗證(MFA + Turnstile) | 2026-09-05 |
| scan-iam-4-user-and-password / md | 盤點證據 | S4 掃描結果:jedi-iam 使用者本體與密碼變更 | 2026-09-26 |
| scan-iam-5-role-and-capability / md | 盤點證據 | S5 掃描結果:jedi-iam 角色與權限能力 | 2026-09-06 |
| scan-iam-6-tenant-org-unit / md | 盤點證據 | S6 掃描結果:jedi-iam 租戶與組織單位 | 2026-09-07 |
| scan-iam-7-login-uiroute-common / md | 盤點證據 | FR-075.S7 掃描報告(重跑版):jedi-iam 的「每個請求怎麼認人」與共用工具 | 2026-09-11 |
| scan-methodology / md | 盤點證據 | 掃描方法與成本控制 | 2026-09-08 |
| scan-progress-tracker / md | 盤點證據 | 資安掃描進度追蹤 | 2026-09-06 |
| scan-tool-explainer / md | 盤點證據 | 我們用什麼工具在找資安問題,它怎麼運作 | 2026-09-06 |
由新到舊。每份是某一棒次交接當下的完整現況快照,看某個時間點「當時知道什麼」請從這裡進。
| 日期 | 文件 | 標題 |
|---|---|---|
| 2026-09-28 | security-scan-STATE / md | 資安掃描 STATE — FR-075/076/077/078/079/081 現況(living) |
| 2026-09-28 | security-scan-LOG / md | 資安掃描 LOG — FR-075 + FR-076 + FR-077 + FR-078(append-only) |
卡片內容(決策紀錄、驗收條件)以 Notion 為準,本頁只記座標。
| 關係 | 卡號 | 標題 | 狀態 |
|---|---|---|---|
| 母案 | CM-1546 | FR-075 jedi-iam 資安掃描系列(6 棒切分,只掃不修) | — |
| 子卡 | CM-1547 | S1 認證與外部身分綁定(11 檔) | 修正待驗證 |
| 子卡 | CM-1548 | S2 授權守門與提權路徑(8 檔) | 修正待驗證 |
| 子卡 | CM-1549 | S3 第二因子與人機驗證(34 檔) | 修正待驗證 |
| 子卡 | CM-1553 | S4 使用者本體與密碼變更(43 檔) | 修正待驗證 |
| 子卡 | CM-1554 | S5 角色與權限能力(49 檔) | 修正待驗證 |
| 子卡 | CM-1555 | S6 租戶與組織單位(47 檔) | 修正待驗證 |
| 子卡 | CM-1556 | S7 登入態、UI 路由、middleware 與共用工具(74 檔) | 修正待驗證 |