---
title: 資安掃描 STATE — FR-075 ＋ FR-076 ＋ FR-077 現況（living）
---

# 資安掃描 STATE（living，只描述此刻）

> 最後更新：2026-09-08，第三任首腦交棒（**決策者裁 FR-077 暫停，改從其他套件開始掃**）。本檔就地 Edit 不留歷史；歷程看 `security-scan-LOG.md`。
> **三個 arc 共用一份 STATE**：FR-075（jedi-iam）、FR-076（License 鏈）、FR-077（遠端 Agent 控制鏈）用同一套方法、同一批 runner 紀律，分開寫會重複。（2026-09-07 決策者裁 FR-077 共用本檔，不另開。）
> **接手先讀 `.claude/skills/security-scan-lead/SKILL.md`**——那是手冊，本檔是現況。

## 🔴 接手第一段：你是首腦，只規劃／驗收／裁決，不自己掃不自己修

角色鐵則見 CLAUDE.md「分析決策人員」條與 `security-scan-lead` skill。接手後照 `closing-and-handoff` skill 的接手側紀律：讀完、盤點完、回報「①自檢 ②現況 ③待辦已就緒等發令」即止。

**冷接自檢三題**（答得出來才算讀懂）：
1. 為什麼 runner 主 session 一定要 Opus 1M，effort 卻要 low？（答案在 skill 第一節）
2. S2 零發現為什麼首腦還是開了 CM-1559？（答案在 skill 第二節第 2 點）
3. CM-1560 的 TLS 項為什麼退回重做？（答案：第一輪做成 `.env` 環境變數，但這是客戶自助的功能設定不是基礎設施設定，判準見「教訓」段第①條，退回後改成設定頁欄位 verify_cert/ca_cert_pem）
4. **FR-077 R1 的七條發現，「不能用」是指哪一件事？**（答案：不是指七條不成立——它們人核兩遍全屬實、修正卡就是照它開的；是指**覆蓋率無法宣稱**：面板全滅使工具正式產出為空、八個重點只觸及一個、密碼學核心零發現分不出「讀過」或「沒讀」。詳見「FR-077 暫停的來龍去脈」段）
5. **為什麼每棒檔數上限從 45 改成 15？**（答案：面板成本＝候選數×3 個 verifier、每個從零讀檔，比研究階段更貴。R1 的 42 檔面板全滅；唯一一次面板跑完是 FR-076 L1 的 10 檔）

## 現況總表

### 掃描棒次（FR-075 七棒 ＋ FR-076 四棒 ＋ FR-077 三棒）

| FR | 棒 | 卡 | 狀態 | 首腦驗收 |
|----|----|----|------|---------|
| 075 | S1 認證與外部身分 | CM-1547 | ✅ Done，8 條 5H3M | ✅ 已驗，開 5 張 |
| 075 | S2 授權守門 | CM-1548 | ✅ Done，0 條 | ✅ 已驗，首腦加開 CM-1559 |
| 075 | S3 MFA＋Turnstile | CM-1549 | ✅ Done，2 條 1H1M | ✅ 已驗，開 2 張 |
| 075 | S4 使用者與密碼 | CM-1553 | ✅ Done，5 條 2C1H2M | ✅ 已驗，開 4 張 |
| 075 | S5 角色與權限 | CM-1554 | ✅ Done，2 條 MEDIUM | ✅ 已驗，開 CM-1585／1586 |
| 075 | S6 租戶與組織 | CM-1555 | **修正待驗證**（狀態卡在掃描失敗記錄，不是真的掃過） | 🔄 **待重派 Opus 1M** |
| 075 | S7 登入態／middleware | CM-1556 | **修正待驗證**（8/9 條越界重複 S1，唯一新發現 Redis TLS 已開 CM-1565）；**核心範圍（middleware／domain service／plugin.py 預設值／login_log／ui_route）從未被真正掃過** | ⏳ **決策者已裁重跑，排 09-06 深夜** |
| 076 | L1 驗章核心 | CM-1567 | ✅ Done，3 條（1 範圍內 HIGH） | ✅ 已驗，開 2 張 |
| 076 | L2 授權狀態 API | CM-1568 | ✅ Done，1 條 LOW＋人工發現 1 HIGH | ✅ 已驗，開 2 張 |
| 076 | L3 LC 簽發核心 | CM-1569 | ✅ Done，2 條範圍內（序號 32 bits／log 遮蔽整串印）＋3 條越界重複 L4 | ✅ 已驗，併入 CM-1583 |
| 076 | L4 LC 網頁後台 | CM-1571 | ✅ Done，4 條 MEDIUM | ✅ 已驗，開 2 張 |
| 077 | R1 agent 身分與註冊（42 檔，jedi monorepo） | CM-1592 | ✅ 掃完 7 條（面板未跑成，runner 逐條核對） | ✅ 已驗（09-08），開 4 張修正＋1 補掃 |
| 077 | R1b 補掃密碼學核心（10 檔，`common/agent_auth/`） | CM-1599 | **待派**（2026-09-08 開卡） | — |
| 077 | R2 任務下發與檔案取用（29 檔，jedi monorepo） | CM-1593 | **待派**（2026-09-07 開卡） | — |
| 077 | R3 主專案宿主接線（17 檔，**BE repo**） | CM-1594 | **待派**（2026-09-07 開卡） | — |

**FR-077 母卡 CM-1591**（2026-09-07 建）。**2026-09-08 決策者裁：FR-077 暫停，改從其他 jedi-* 套件開始掃。** R1 已完成並驗收（7 條，4 張修正卡＋1 補掃棒已開），其餘四棒（R1b／R2a／R2b／R3）卡都開好了、範圍與重點都寫死在卡裡，**隨時可以續**，但目前不派。修正卡 CM-1595～1598 同樣待派（見下方修正卡表）。

**FR-075 母卡 CM-1546、FR-076 母卡 CM-1566 本身狀態都還是「Not started」**——那是母卡自己的狀態欄，不代表子卡沒做；子卡才是實際進度。母卡收 Done 的時機是全部子卡（含 S6/S7 重跑、CM-1559）都收尾之後。

**掃描 prompt** 見 skill 第六節，換卡號與檔數。

### 修正卡（28 張，Done 16／進行中 1／盤點中 1／待派 4／暫緩 2／掃描失敗待重跑不算卡）

| 卡 | 修什麼 | 嚴重度 | 狀態 | commit |
|----|--------|--------|------|--------|
| CM-1575 | 忘記密碼端點外洩重設憑證 | 🔴 CRITICAL | ✅ Done | jedi-iam `a9edf1d` |
| CM-1557 | MFA 驗證碼無次數限制 | HIGH | ✅ Done | jedi-iam `b51b914`, FE `d3283e5` |
| CM-1560 | LDAP 三洞（bind／filter escape／TLS） | HIGH | ✅ Done（TLS 項退回重做過一次） | jedi-iam `9b353ee`→`20c6713`, BE `3ad876ae`→`f503fba3`, FE `78903b2` |
| CM-1562 | 綁定外部身分無本人檢查 | HIGH | ✅ Done | jedi-iam `76a8c2d` |
| CM-1561 | Google 登入殼 | HIGH | ✅ Done（**決策者改裁：關閉不拔除**） | jedi-iam `d28e364`, BE `d08bc34c` |
| CM-1576 | 自助 profile 自我提權 | HIGH | ✅ Done | jedi-iam `7cf3cf2` |
| CM-1572 | 驗章前無界解壓縮 | HIGH | ✅ Done（③ MAX_CONTENT_LENGTH 由 CM-1587 承接，已裁 50MB） | jedi-integrity 同款兩處一併修 |
| CM-1579 | 停權可被換照解除 | HIGH（SaaS） | Not started（**決策者已改裁：現在做，方案 A**，不再暫緩） | — |
| CM-1558 | Turnstile 缺金鑰 fail-open | MEDIUM | ✅ Done | jedi-iam `2bf2003`, FE `52a40c4` |
| CM-1559 | RLS fail-open | MEDIUM，影響面最廣 | **In progress**（首腦已派 Opus 做第一步盤點，卡內盤點指引完整） | — |
| CM-1563 | 帳號枚舉統一 401 | MEDIUM | ✅ Done | jedi-iam `6a13d96` |
| CM-1564 | LDAP 連線測試改位址強制重輸密碼 | MEDIUM | ✅ Done | BE `d4d1b0e4`, FE `0f1d0ed` |
| CM-1565 | Redis TLS 不驗憑證 | MEDIUM | ✅ Done | jedi-iam `4c7579c`, BE `83c5b118` |
| CM-1573 | jedi-issue PAT 外洩處置 | MEDIUM | ✅ Done（決策者裁 token 早已註銷，跳過後台再確認） | jedi monorepo `ed62d8a` |
| CM-1577 | update_user 改密碼不驗強度 | MEDIUM | ✅ Done | jedi-iam `eaa8de7`, BE `b67e9cdd` |
| CM-1578 | Excel 上傳目錄用未驗證 login_name | MEDIUM | ✅ Done | jedi-iam `608d077` |
| CM-1580 | 跨租戶重複用照部分唯一索引 | LOW | ✅ Done（DEV 已建索引；STG/POC 套 migration 等上版） | — |
| CM-1581 | build 守門路徑 bug | 小 fix | ✅ Done | `4b527704` |
| CM-1582 | 客戶包公鑰白名單 | — | ⏸ 暫緩（維持） | — |
| CM-1583 | LC 開通端點防猜＋計數表＋log 遮蔽＋補發復活（七項） | HIGH | ✅ Done（⑦ 補發語意採 B 案：產新碼作廢舊碼） | LC `a68200c` |
| CM-1584 | LC 登入 next 開放導轉 | MEDIUM | ✅ Done | license_center `58c0e98` |
| CM-1585 | 角色讀取端點無守門（S5 F1） | MEDIUM 偏 HIGH | ✅ Done | jedi-iam `4984e1e`, FE `2268571` |
| CM-1586 | 失效角色算成有效（S5 F2） | MEDIUM | ✅ Done | jedi-iam `dbb96aa`, BE `7097774` |
| CM-1587 | 全站請求 body 上限（CM-1572③ 衍生） | MEDIUM | ✅ Done（決策者裁 50MB） | BE `f867540f`+`2ea76ef7`, FE `21157820` |
| **CM-1595** | **FR-077**：agent 控制面四端點不驗身分（F1+F2+F3+F5）＋nginx 連帶 | 🔴 **CRITICAL** | **待派**（隨 FR-077 暫停） | — |
| **CM-1596** | **FR-077**：健康檢查 SSRF（F4） | MEDIUM | **待派** | — |
| **CM-1597** | **FR-077**：enroll token 永久有效＋重註冊接管（F6） | MEDIUM | **待派**（依賴 1595，序列做） | — |
| **CM-1598** | **FR-077**：`jedi-common/.env` 受版控（F7 越界） | LOW | **待派** | — |
| CM-1595 | 控制面四端點驗 agent 簽章、fail closed、任務綁歸屬（F1+F2+F3+F5）＋ nginx 連帶 | 🔴 CRITICAL | 待派 | — |
| CM-1596 | 健康檢查 SSRF（F4） | MEDIUM | 待派 | — |
| CM-1597 | enroll token 到期／次數＋重註冊持有證明（F6，依賴 CM-1595） | MEDIUM | 待派 | — |
| CM-1598 | `jedi-common/.env` 受版控處置（F7 越界） | LOW | 待派 | — |

**修正 prompt** 見 skill 第六節。修正卡 runner 用 Sonnet 5 即可（S5/S6/S7 掃描棒本身才需要 Opus 1M）。

### 派工衝突規則（多數已隨修正完成失效，僅列尚未收口的）

- **CM-1559** 原規劃等 S5／S6／S7 全掃完才派——現況 S5 已完成、S6/S7 未完成，但首腦判斷 CM-1559 是獨立主題（session_scope fail-open），**已提前派出做第一步盤點**，不再卡 S6/S7
- **同套件的卡共用 poetry path dependency**：改動 BE 重啟即生效，**path 改動不 commit**，feature 完成後還原 pin 一起 commit——CM-1579 動手時要注意這條
- 決策者 2026-09-06 裁「先把 FR-076（L1/L2 產出）修完再動 FR-075」——**這條已達成**，FR-076 八張修正卡全 Done，FR-075 也已完成大半

## 已裁決事項（不要重問）

| 事項 | 裁決 | 日期 |
|------|------|------|
| 掃描工具 | 用 claude-security plugin，不改人工審 | 09-05 |
| 切棒方式 | 按業務模組垂直切，不按 DDD 分層 | 09-05 |
| 模型 | runner 主 session Opus 1M（限 S4 以上檔數多的棒） | 09-06 |
| Google 登入殼（CM-1561） | **改裁：關閉不拔除**（原裁拔除，第二任首腦改） | 09-06 |
| 停權繞過（CM-1579） | **改裁：現在做，方案 A**（原裁綁 SaaS 上線暫緩，第二任首腦改） | 09-06 |
| 三環境硬編公鑰（CM-1582） | 維持暫緩，綁正式 LC；守門 bug 先修（CM-1581，已 Done） | 09-06 |
| CM-1575 上版時機 | 不做 nginx 臨時節流；等 CM-1583 完成後與 LC 修正一起上版 | 09-06 |
| CM-1583 ⑦ 補發語意 | B 案：補發產新序號、舊碼作廢 | 09-06 |
| CM-1587 body 上限 | 50MB（因 CM-1583 簽章 manifest 近 1MB，runner 由 64KB 改 16MB 再由決策者定 50MB） | 09-06 |
| CM-1560 TLS 設定放哪 | **改裁：設定頁欄位（verify_cert/ca_cert_pem），不用 .env 變數**（原第一輪做成 .env，退回重做） | 09-06 |
| CM-1573 撤銷確認 | 決策者裁 token 早已註銷，跳過後台再確認，直接處理 dist/Nexus 殘留 | 09-06 |
| **產品時程** | 第一版是落地版，SaaS 預留。修正優先序判準見 `docs/claude/memory/project_first_release_is_host_saas_reserved.md` | 09-06 |
| Memory 共享 | 搬進 `docs/claude/memory/` 入版控 | 09-06 |
| **FR-077 切棒** | 三棒（R1 身分 42 檔／R2 任務＋檔案 29 檔／R3 主專案宿主接線 17 檔）。切三棒而非兩棒，是因為 agent 鏈被 repo 邊界切成三段而 scanRoot 只能指一個目錄；R3 檔少（17 檔 881 行）但密度最高——套件把所有安全決策外包給宿主，真正的答案在那 17 檔裡 | 09-07 |
| **FR-077 STATE** | 共用本檔，不另開 | 09-07 |
| **FR-077 F1 嚴重度** | 升 **CRITICAL**（原 runner 判 HIGH）——無認證＋跨租戶＋洩漏客戶第三方憑證三條件全中 | 09-08 |
| **FR-077 修正卡切法** | F1+F2+F3+F5 併一張（CM-1595，同一套 agent 認證機制）；nginx 併進當「連帶」不另開卡（它不能當唯一防線） | 09-08 |
| **每棒檔數上限改 15** | 原 10～45 檔。R1 的 42 檔面板全滅（105 verifier 全死、21 票 0 投）；唯一一次面板跑完是 FR-076 L1 的 10 檔。**新尺：每棒 ≤15 檔** | 09-08 |
| **報告格式** | **開頭必須是白話總覽表**（`# / 嚴重度 / 這是什麼問題（白話）/ 出事會怎樣 / 要先有什麼才打得到 / 位置 / 修正卡`）＋「這份結果的可信度」段。R1 報告已改成此格式可抄 | 09-08 |
| **🔴 FR-077 暫停** | **改從其他 jedi-* 套件開始掃**。理由：決策者判定「掃出來都不能用」——面板全滅使工具正式產出為空、覆蓋率無法宣稱，靠人工補核不可持續 | 09-08 |
| **FR-077 F1 嚴重度** | 升 **CRITICAL**（無認證＋跨租戶＋洩漏第三方憑證三條件全中；UUID 業界從不當秘密） | 09-08 |
| **FR-077 A／B 併卡** | F1+F2+F3+F5 併一張（CM-1595），同一套 agent 認證機制、共用測試，避免兩個 runner 各寫一套 | 09-08 |
| **FR-077 nginx** | 併進 CM-1595 當連帶，不另開卡——加分項非主修法，獨立開卡會誤以為補了 nginx 就算修好；驗收條件明寫應用層 fail closed 為必要 | 09-08 |
| **FR-077 補掃** | 開 R1b（CM-1599）——密碼學核心（CA／JWT）零發現在面板未跑下不可信 | 09-08 |
| **FR-077 R2／R3** | 現在就派——掃不同檔與本批決策無關，R3 結果回饋到 CM-1595 | 09-08 |

## 待決策者裁的事項

1. **CM-1559 第一步盤點結果**——等 runner 回寫盤點清單後裁第二／三步範圍
2. **S6 要不要用 Opus 1M 重派**（原掃描是失敗記錄，非乾淨無發現）
3. **S7 要不要重跑**（核心範圍 middleware／domain service／plugin.py 預設值／login_log／ui_route 從未被真正掃到；重跑要收窄掉 `infra/adapter/authenticate_adapter/` 與 `user_auth_provider_service.py` 避免再度越界重複 S1）
4. **上版時機**：FR-075／FR-076 修正卡已大致收口，何時把 jedi-iam／jedi-license-runtime／license_center 一起發版上 STG/POC
5. **FR-077 的 CRITICAL 要不要先修**（CM-1595）——arc 雖暫停，但 F1 是「不需帳號即可拿走客戶自己機器帳密」，**修正卡與 arc 是否要一起停，決策者未明示**。首腦建議：**掃描停、修正照做**，1595 不該等
6. **下一批要掃哪些套件、掃到什麼程度**——首腦已備妥 25 支全套件排名（見下方「全套件掃描排名」段），等決策者挑

## 上版待辦（等 S6/S7/CM-1559 收尾或決策者裁定即可啟動）

- **jedi-iam**：10 張修正卡（1557/1560/1561/1562/1563/1565/1576/1577/1578/1585/1586）待發版 → 主專案 `pyproject.toml` pin → 重出 image → 部署 STG → 部署 POC
- **License Center（LC）**：1583/1584 兩張走 LC 部署四步（pull→依賴→alembic PYTHONPATH=src→restart）；1583 帶兩支 alembic migration（皆 nullable）需套 STG/POC
- **主專案 BE**：1580 的部分唯一索引 migration 需套 STG/POC（DEV 已建）
- **STG 上版行為變化提醒**：
  - 1565（Redis TLS）——若 STG/POC 的 Redis 沒開 TLS，此修正不影響行為；若已開 TLS 但憑證有問題，上版後會直接擋連線，上版前先確認憑證鏈正確
  - 1560（LDAP TLS）——原本可能允許不驗憑證的 LDAP 連線，上版後預設驗證，若 STG/POC 有接 LDAP 且憑證未配置好會直接連不上，上版前先跟環境負責人確認

## 教訓（第二任首腦新增，累加在第一任的方法論教訓之後）

1. **判斷「.env 變數」還是「設定頁欄位」，看誰要調它、調的頻率**：客戶自助能改的功能設定（如 LDAP 是否驗憑證、憑證內容）走設定頁欄位，跟著 tenant/連線設定走；只有部署階段定死、客戶不該碰的基礎設施設定才走 `.env`。CM-1560 的 TLS 項第一輪做成 `.env` 環境變數，被退回重做——原因是「要不要驗 LDAP 憑證」與「憑證內容」屬於客戶會依自己 LDAP 伺服器狀況調整的功能設定，硬編進 `.env` 意味著改一次要重啟服務甚至要工程師介入，不符合這類設定該有的自助性。跟現有 LDAP 連線設定（host/port/bind DN 等）擺在一起，就知道判準。
2. **驗收要親自跑測試，不能信 runner 自述**：CM-1587 的驗收就是這樣抓到問題的——runner 回報已完成，但沒有把新 error code 登記進「凍結 error code 基準表」，這件事只有實際去比對基準表才會發現，光看 commit message 或 runner 的文字描述看不出來。往後每張修正卡驗收，除了看 diff，還要跑一次卡片要求的測試指令，不能只信 runner 的「已驗證」宣稱。
4. **面板全滅時「結果能不能用」要分兩層答，不要籠統說「不能用」**：「這幾條存在嗎」與「只有這幾條嗎」是兩個問題。前者靠人工開檔核對就能回答得比面板還可靠（打開檔案那幾行就是那樣寫的，是事實陳述不是推論）；後者只有工具跑完面板才答得出來。FR-077 R1 就是前者成立、後者不成立——**修正卡照開沒問題，但不能宣稱這個套件掃過了**。交接與報告時要把這兩層分開寫，否則接手者會誤以為七條也不可信而重掃（浪費）或誤以為套件乾淨（危險）。
5. **報告開頭必須是白話總覽表，這是硬規則不是風格偏好**：R1 報告第一版把「執行概況（agent 數／token 數）」與「面板為什麼全滅」放在最前面，要捲到第 150 行才看得到第一條發現在講什麼，決策者的評語是「連工程師都不想看」。改成開頭一張表（`# / 嚴重度 / 這是什麼問題（白話）/ 出事會怎樣 / 要先有什麼才打得到 / 位置 / 修正卡`）＋「這份結果的可信度」段之後才可用。**新開的掃描卡都要把這條寫進「交付什麼」**，R1 報告可直接抄格式。
6. **runner 自行偏離卡片建議時，要看理由合不合理，不是照卡硬套**：CM-1583 的卡片原本建議 body 上限 64KB，runner 實際做的時候發現簽章 manifest 檔案本身可能接近 1MB，因此改成 16MB 才不會誤傷正常流程，首腦驗收時認同這個調整，最終決策者再定案 50MB（考慮到 CM-1572 也有共用需求）。這類「runner 發現卡片給的數字/範圍不切實際而自行調整」不是違規，只要理由站得住腳、有具體證據（如「簽章檔案實測大小」），首腦應該認同並往上呈報決策者定案，而不是要求 runner 機械照卡片原始數字做。

## FR-077 補充（2026-09-07 第三任首腦）

**這個 arc 的風險形狀與前兩個不同**，接手時要知道：

1. **控制面四個端點刻意不掛任何 user 認證**（register／heartbeat／ack／result）。這是設計不是疏漏——agent 不帶 user JWT，身分靠 mTLS 在上游 nginx 終結。**但 BE 自己不終結 TLS、拿不到 client 憑證**，所以「是哪一台 agent」全靠 payload 或 header 自報。這是本 arc 的核心問題面。
2. **首腦讀碼時已看到的最大嫌疑**（寫進卡片「重點看什麼」，**尚未經任何驗證**）：
   - `ack_task(uid)` / `receive_result(uid, payload)` 參數只有 task uid，**沒有 agent_uid、沒有 tenant 檢查**——任何 agent 拿到別人的 task uid 就能替它 ack、替它回報成功並塞任意 `result_ref`。jedi-detection 的 docstring 自己寫了「ack / result 根本不識別身分」，但**沒有人判斷過可不可接受**。
   - `heartbeat()` 的身分 fallback `get_one_remote_agent(device_fingerprint=device_uuid)` **沒帶 tenant_id**，而 `register()` 的同款查詢**有帶**。兩者都跑在無 user context 的 super admin scope。
   - enroll token 全租戶共用一組、**無到期、無次數上限、無機器綁定**，進 installer 發給客戶。
   - 指紋撞號守門對**已離線**的持有列刻意放行（門檻 900 秒），理由是客戶重灌場景。
3. **本套件的程式碼註解寫得極為詳盡且處處自我辯護**——每個可疑設計都有一段 docstring 解釋為什麼安全。這正是工具的第二個盲點（會被註解說服，FR-075 的 S2 就是這樣八檔零發現卻漏掉真洞）。三張卡都寫了這個警告。

## 🔴 FR-077 暫停的來龍去脈（2026-09-08，交棒重點）

**決策者原話：「掃出來都不能用，我決定從其他套件開始掃。」** 接手者要理解這句話指的是什麼、以及它是不是等於「R1 的發現不成立」——**不是**。

### 發生了什麼

R1（42 檔）跑了 2 小時 21 分、158 萬 token，**研究階段完整完成**（2/2 研究員回報、8 條候選去重成 7 條），但**三人驗證面板全滅**——105 個 verifier 全部撞 session 額度上限，21 張票 0 張投出。工具的正式 `findings` 因此是空陣列，stamp 記 `verification.status: unverified`。

runner 沒有重跑（正確），改從 workflow journal 撈回候選、**七條全部人工開檔核對**；首腦再親自複核 F1／F2／F3 的行號、grep BE 與 FE 兩個 repo 確認三個 nginx 設定檔皆無 `ssl_verify_client`、追明文憑證流向。**七條全部屬實。**

### 「不能用」指的是什麼

分兩件事，不要混：

| | 可信嗎 | 為什麼 |
|---|---|---|
| **這七條存在** | ✅ **可信** | 每條都是「打開檔案，那幾行就是那樣寫的」——事實陳述不是推論。人核兩遍（runner 逐條＋首腦複核關鍵條）。**修正卡 CM-1595～1598 是照這個開的，依據紮實。** |
| **「只有這七條」** | ❌ **不可信** | 面板沒跑＝沒有「工具背書」的產出；卡片列的八個重點只實質觸及一個；密碼學核心（`ca.py`／`jwt_util.py`）零發現但分不出「讀過沒問題」與「根本沒讀」 |

決策者的判斷是針對**第二列**：一個掃描工具跑完之後，**正式產出是空的、覆蓋率無法宣稱、要靠人工補核才有東西**，這樣的產出對「證明某個套件掃過了」沒有價值。這個判斷是對的。

### 首腦當時提出、但決策者選擇不走的路

首腦建議把每棒壓到 15 檔以內（FR-076 L1 的 10 檔是唯一一次面板跑完的紀錄），並已據此把 R2 拆成 R2a（18 檔）＋R2b（13 檔）。決策者選擇**先換套件**而非繼續調參數——理由未逐字記錄，但合理推斷是：與其在同一個套件上反覆試工具的極限，不如先去掃風險更高、且範圍天然就小的套件（見下方排名，前段有多支 13～34 檔的套件，天生就在面板撐得住的量級）。

### 續行時要知道的

四棒的卡都開好了、範圍與「重點看什麼」都寫死在卡裡，**檔數已按新尺（≤15 檔）調過**，隨時可續：

| 棒 | 卡 | 檔數 | 備註 |
|---|---|---|---|
| R1b 補掃密碼學核心 | CM-1599 | 10 | 與 FR-076 L1 同量級，**最有把握跑完面板的一棒** |
| R2a 任務下發與狀態機 | CM-1593 | 18 | 卡尾有「範圍收窄」段，**以那段為準**（原卡寫 29 檔） |
| R2b 檔案取用與 agent 連線 | CM-1601 | 13 | **重疊帶入** R2a 兩支檔，刻意的，見下 |
| R3 主專案宿主接線 | CM-1594 | 17 | scanRoot 是 **BE repo**，與其他棒不同 |

**R2a／R2b 的重疊要保留**：檔案下載授權判的是「這個檔案是不是該 agent 名下未完成任務引用的」——問題前半在 R2b（`agent_file_access_service.py`）、後半在 R2a（狀態機與 repo query）。R2b 因此額外帶入 `agent_task_domain_service.py` 與 `agent_task_repo_impl.py`。**重複報由首腦驗收時挑掉；接縫沒人看才是真的損失。**

### 🔴 修正卡不該跟著停（首腦意見，待決策者裁）

CM-1595 是 **CRITICAL**：不需任何帳號憑證，打一個 HTTP 請求到心跳端點即可拿走該租戶掃描工具的**明文客戶憑證**（客戶自己的 SonarQube token、SSH／WinRM 帳密），且可跨租戶。決策者裁的是「**掃描**改從其他套件開始」，沒有明示修正卡也停。**首腦建議：掃描停、CM-1595 照派。**

---

## 全套件掃描排名（首腦 2026-09-08 備妥，供決策者挑下一批）

檔數為 **attack-surface 口徑**（已排除 tests／dist／docs）。棒數按**新尺每棒 ≤15 檔**推算，時數按實測**每棒約 70 分鐘**。

| # | 套件 | 檔數 | 行數 | 棒 | 預估 | 現況 |
|---|---|---:|---:|---:|---:|---|
| 1 | jedi-ai-bot | 13 | 632 | 1 | 1.2h | |
| 2 | jedi-integrity | 20 | 3,178 | 2 | 2.4h | |
| 3 | jedi-bulletin | 29 | 847 | 2 | 2.4h | |
| 4 | jedi-device | 29 | 962 | 2 | 2.4h | |
| 5 | jedi-information-system | 31 | 1,344 | 3 | 3.6h | |
| 6 | jedi-system-config | 31 | 1,176 | 3 | 3.6h | |
| 7 | jedi-log-forwarding | 32 | 2,263 | 3 | 3.6h | |
| 8 | jedi-notification | 32 | 1,011 | 3 | 3.6h | |
| 9 | jedi-ai-dashboard | 33 | 2,296 | 3 | 3.6h | |
| 10 | jedi-system-menu | 34 | 1,199 | 3 | 3.6h | |
| 11 | jedi-log | 41 | 1,305 | 3 | 3.6h | |
| 12 | jedi-evidence-classification | 45 | 3,955 | 3 | 3.6h | |
| 13 | jedi-license-runtime | 49 | 3,963 | 4 | 4.8h | ✅ FR-076 掃完 |
| 14 | jedi-file-upload | 61 | 2,510 | 5 | 6.0h | |
| 15 | jedi-remote-agent | 65 | 3,032 | 5 | 6.0h | 🔄 FR-077 R1 完成，餘暫停 |
| 16 | jedi-flow-engine | 71 | 6,956 | 5 | 6.0h | |
| 17 | jedi-task-platform | 83 | 3,585 | 6 | 7.2h | |
| 18 | jedi-common | 92 | 3,454 | 7 | 8.4h | ⚠️ 只有第一輪未驗證掃描，**不算數** |
| 19 | jedi-participant | 103 | 5,391 | 7 | 8.4h | |
| 20 | jedi-issue | 129 | 3,599 | 9 | 10.8h | |
| 21 | jedi-detection | 151 | 17,013 | 11 | 13.2h | 🔄 僅 agent 相關 11 檔借進 FR-077，**餘 140 檔未掃** |
| 22 | jedi-survey | 153 | 11,315 | 11 | 13.2h | |
| 23 | jedi-compliance-audit | 168 | 13,733 | 12 | 14.4h | |
| 24 | jedi-iam | 290 | 15,421 | 20 | 24.0h | ✅ FR-075 掃完（S7 待重跑） |
| 25 | jedi-oscal-v2 | 364 | 15,837 | 25 | 30.0h | |

**未掃合計約 111 棒、133 小時**（純掃描，不含驗收／開卡／修正）。

### 首腦建議的執行順序（按風險，不是按檔數）

| 優先 | 套件 | 檔數／時數 | 為什麼 |
|---|---|---|---|
| **1** | **jedi-common** | 92 / 8.4h | **全部套件都 import 它**——`session_scope`、`@transaction`、RLS 注入、error handler、response 信封都在這。CM-1559 那條 fail-open 的根就在這裡，而它**至今沒有一次算數的掃描**（第一輪 medium 半途喊停、未經面板）。它出問題等於 25 支全中 |
| **2** | **jedi-integrity** | 20 / 2.4h | 檔少但全是簽章驗證與完整性。FR-076 已在它身上撞到 HIGH（無界解壓縮 CM-1572），那還是順手發現的。**CP 值最高** |
| **3** | **jedi-file-upload** | 61 / 6h | 檔案上傳下載、儲存後端切換（local／minio／remote_agent）。路徑穿越與任意檔案讀取的天然溫床 |
| **4** | **jedi-detection**（agent 以外 140 檔） | 140 / 12h | **客戶憑證解密在這**（`_resolve_tool_credentials`）、掃描參數會變成 agent 端執行的指令 |
| **5** | **jedi-participant** | 103 / 8.4h | 專案成員與角色——授權判定的資料源。jedi-iam 管「你是誰」，這支管「你在這個專案能幹嘛」 |

**可以最後排的**（讀取展示型，攻擊面小）：jedi-bulletin／jedi-system-menu／jedi-log／jedi-log-forwarding／jedi-notification／jedi-ai-dashboard／jedi-information-system，約 200 檔、20 小時。

**jedi-oscal-v2 建議獨立 arc**：364 檔最大一支，但它是文件格式的 parser／serializer，風險形狀不同（XXE、解析炸彈、資源耗盡），與授權鏈掃描的「重點看什麼」完全不同，混在一起會讓卡片失焦。

### 🔴 排掃描計畫時的兩個陷阱（FR-077 換來的）

1. **「某某套件掃過了」這句話要問範圍**。jedi-detection 只被借走 11 檔，剩 140 檔沒動；jedi-common 只有一次未驗證的半途掃描。**看報告要看 scope 清單，不是看套件名。**
2. **攻擊路徑會跨套件，不能按 repo 邊界切**。agent 檔案下載這條路徑橫跨 jedi-detection（授權判定）→ jedi-remote-agent（任務狀態）→ 主專案（route 與 mTLS adapter）。套件邊界是按「業務歸屬」畫的，攻擊路徑是按「資料怎麼流」走的，**兩者不重合**。登入、授權、檔案上傳都有同樣情形。排計畫時要先問「這條路徑完整走過哪些包」，再決定一棒的範圍。

---

## 接手第一件事的建議

1. **讀完就停，等決策者發令**（接手側紀律，見本檔開頭）。下面是「已就緒的選項清單」，不是執行授權
2. **決策者已裁：從其他套件開始掃**——排名與建議順序見上方「全套件掃描排名」段。首腦建議第一批 **jedi-common**（92 檔／7 棒，全套件的地基，至今無算數掃描）或 **jedi-integrity**（20 檔／2 棒，CP 值最高）。開新 FR 前先去 `docs/features/README.md` 查最大整數號 +1（**目前最大 FR-077**，下一個是 FR-078）
3. **FR-077 的 CRITICAL（CM-1595）要不要照派**——首腦建議「掃描停、修正照做」，但決策者未明示，**這是接手後該問的第一件事**
4. **CM-1559**：等盤點回寫，讀完決定第二／三步能不能派
5. **S6**：決定要不要重派 Opus 1M（原掃描是失敗記錄）
6. **S7**：決策者已裁重跑，深夜放行後派 Opus 1M（prompt 見 skill 第六節，CM-1556 檔數 74）
4. **上版**：若決策者已準備好放行，可以開始規劃 jedi-iam／LC 批次發版 + STG/POC 部署順序
7. **FR-077 四棒卡都開好但暫停**（CM-1599／1593／1601／1594），要續時 prompt 見 skill 第六節，檔數 10／18／13／17。**R2a（CM-1593）以卡尾「範圍收窄」段為準**，R3 的 scanRoot 是 **BE repo** 不是 jedi monorepo

## 座標

- 三個 FR：`docs/features/FR-075-2609-jedi-package-security-audit/`、`docs/features/FR-076-2609-license-chain-security-scan/`、`docs/features/FR-077-2609-remote-agent-security-scan/`
- 方法論與失敗紀錄：FR-075 的 `scan-methodology.md`
- 母卡：FR-075 CM-1546、FR-076 CM-1566、FR-077 CM-1591（各棒驗收表都 append 在母卡）
- 掃描產物（不入版控）：`<scanRoot>/CLAUDE-SECURITY-<ts>/`，stamp 檔在裡面
- branch：BE／jedi 套件／license_center 三個 repo 都在 `feature/FR-075`，**都未 push**
- 建卡：`scripts/notion_create_case.py`
