現況(2026-10-01):本文是 2026-09-26 的分類快照。文中「未修/待裁」的項目後來已全數處理——FR-114 第 8 批 12 組(CM-2211~2220 等)已修並隨 1.21.0 出貨;1.21.1 再修授權讀取(CM-2369)等。最終狀態以
docs/security-report/SUMMARY.md問題總表為準(已修 206、拆除退場 15、裁定不修 12、SaaS 前必做 1)。以下內文保留當時的分類過程。
掃描線全案收口後,所有還沒修的項目經決策者 2026-09-26 逐項裁定,整理成這份交 FR-114 開第 8 批。 分類底稿:同目錄
remaining-classification.md(CM-2209)。檔:行已在修正線(BE1516d90bc、套件e758cd6a)核過;行號會漂,開卡前 grep 一次。
讀者:FR-114 首腦。決策者已經全部裁完,這份裡沒有要再問的,照著開卡即可。
幾個詞:守門=程式裡檢查「你有沒有資格做這件事」的那段;修正線=fix/security-b1 工作區;出貨基線=新客戶安裝時拿到的資料庫結構(scripts/init/02-schema.sql)。
🔴 開卡前先看這三件:
compliance.evidence_classification_runs 都是 0 筆舊線資料(run_folder_id IS NOT NULL)。原本 T-6.1 保留舊路由的理由(POC 可能有客戶舊結果)已不成立。DEV 有 8 筆測試資料,刪路由後那 8 筆打不開屬預期。SHARED 值域、8-E 第 215 項兩張表的新增規則。都追加到 CM-2197。現況:✅ 已修(CM-2211,commit fe928859f/套件 cdb83526,1.21.0 出貨)。
這組是什麼病:只驗「有登入」或「是網址上那個專案的人」,沒驗「你要動的東西屬不屬於那個專案/公司」。一律用 common.authz 既有守門,不另寫。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 205 | 中 | 還原摘要報告歷史版本時,不檢查那個版本是不是這份報告的,可以拿別份報告的內容蓋掉自己這份 | app/project_summary_report/service/project_summary_report_history_service.py:66-85 |
取出 history 後比對 history.report_id == report.id,不符回 404(與第 94 項同寫法) |
| 總表 202 | 低 | 同公司任何人把網址換成別的專案,就看得到那個專案這一輪任務的完成數 | 套件 jedi-task-platform/jedi_task_platform/task/app/service/task_execution_service.py:139-141 |
比照同檔 _check_manager 先解析專案,再 assert_project_participant |
| 總表 214 | 低 | 人員對帳四處查詢收了公司編號卻沒用,平台管理員身分下跨所有客戶比對 | domain/oscal/service/reconciliation/person_reconciler.py:18,34,49,66 |
比照 organization_reconciler 加 tenant_id 條件 |
| 總表 191 | 低 | 驗證雲端硬碟應用程式憑證的端點,只查平台管理員、沒查「儲存設定」能力點 | app/cloud_integration/service/drive_app_credential_verify_service.py:71(route api/cloud_integration/routes/drive_app_credential_verify_route.py 只掛 jwt_required) |
補 storage-config 對應能力點。⚠️ CM-2209 文件說「修正線已收」是錯的:require_platform_admin() 從 CM-1900 就在,缺的是能力點 |
| 總表 203 | 低 | 孤兒資料清理如果某次排程沒帶身分,會把全部正常資料判成孤兒整批刪(今天有帶身分,不觸發) | infra/flow_control/repository/job_binding_orphan_query.py:87,102,125(三處 NOT EXISTS) |
刪之前先確認「看得到的任務數 > 0」,看不到就中止並記 ERROR |
現況:✅ 已修(CM-2212,commit c8534bfcb/8f5755f1d,1.21.0 出貨)。
這組是什麼病:回廠診斷包與伺服器紀錄裡,密碼、登入權杖以各種寫法原樣留下。總表第 162 項(CM-2193)只補「KEY=值」一種寫法就是前車之鑑,這組要一次修完。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 186 | 中 | 即時通訊服務逐筆記錄封包,登入權杖明文進容器紀錄;診斷包收容器紀錄時沒遮 | core/app_factory.py:189,191;infra/support/collector/host_collector.py:136-156、infra/support/collector/staged_collector.py:128-153 |
logger/engineio_logger 改關或降級;兩支收集器都過 mask_log_lines |
| 總表 209 | 中 | 診斷包設定快照遇到跨多行的值只遮第一行 | infra/support/collector/container_collector.py:94 |
先遮值再串 KEY=值,或以整個值為單位遮 |
| 總表 162 剩餘 | 中 | 遮罩還認不得 password='值'、"key": "值"、連線字串帳密、export KEY=值;資料庫紀錄走最弱的 mask_json_like;打包前沒統一過一道 |
infra/support/diag_masking.py:164-169;db_reader.py:237、diag_slice_domain_service.py:245;組裝入口 diag_bundle_app_service.py:115-120 |
規則補齊;資料庫紀錄改走日誌遮罩;打包前統一過一道 |
| 總表 211 | 低 | API 連線紀錄的網址欄不在遮罩清單 | domain/support/entity/diag_bundle.py:30 |
MASKED_API_LOG_COLUMNS 加 url |
驗收:用 FR-120 U10/U11 那幾種假密碼寫法各塞一筆,產包後整包 grep 找不到原值。總表 207(寄信失敗寫密碼)已由 CM-2111 修掉,但它暴露的 password='值' 寫法要在本卡補進規則。
現況:✅ 已修(CM-2213,commit a5804a990/bde8f9d16,1.21.0 出貨)。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 204 | 中 | 摘要報告匯出 PDF 時圖片白名單放行 SVG,SVG 可指向內網網址讓伺服器去抓 | api/project_summary_report/routes/project_summary_report_route.py:42-49、:166 |
排除 data:image/svg+xml,且 write_pdf 給拒絕一切外部網址的 url_fetcher(首腦本機重現過,兩道都做) |
| 總表 199 | 低 | 匯出任務 Excel 時,以 = + - @ 開頭的欄位會被 Excel 當公式 |
app/flow_control/service/job_import_service.py:135-180 |
沿用 CM-2189 那支強制文字的中和函式,不要寫第四份 |
| 總表 200 | 低 | 批次完成通知信把操作者暱稱當網頁程式碼塞進信裡,改暱稱就能在信裡放可點的釣魚連結 | app/flow_control/service/job_batch_complete_service.py:95,105;同型 workflow_execution_service.py:1219、project_service.py:776 |
三處暱稱都 HTML 跳脫(決策者 09-26 裁照修) |
| 總表 197 | 低 | 依名稱找雲端資料夾只跳脫單引號、沒跳脫反斜線 | infra/cloud_integration/google_drive/google_drive_api_client.py:121 |
先跳脫 \ 再跳脫 ' |
| 總表 196 | 低 | 雲端硬碟通知 token 比對不是固定時間比對 | app/cloud_integration/service/google_drive_webhook_service.py:94 |
!= 改 hmac.compare_digest |
現況:✅ 已修(CM-2214,commit d39181f3b/046553756,1.21.0 出貨)。
會改到安裝指令稿,出包後要實裝測一次。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 208 | 中 | 診斷指令用猜得到的名字建暫存資料夾、不檢查捷徑,容器內一般權限的人可騙 root 寫到別處 | scripts/installer/guidant diag 段(:720、:775 附近 mkdir -p "$stage_host";報告的 :700-708 已漂移) |
改 mktemp -d 建在只有 root 可寫處,或建立前檢查不存在且非符號連結 |
| 總表 210 | 低 | 出貨主機預先蒐集只照索引檔路徑讀檔,服務名稱可塞 ../ |
infra/support/collector/staged_collector.py:90,140 |
服務名稱白名單;讀檔前 realpath 確認在暫存目錄內 |
| 總表 206 | 低 | 匯出診斷包時起始帶時區、結束不帶,程式當掉回 500 | app/support/service/diag_bundle_export_service.py:76 _resolve_window |
兩邊統一轉成帶時區 |
現況:✅ 已修(CM-2215,commit 822216b6c,1.21.0 出貨)。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 183 | 低 | 安裝精靈設定碼塞中文或特殊字元,伺服器回 500 並寫錯誤紀錄 | common/setup/setup_token.py:92 |
比對前只收英數字,或兩邊 .encode() 再比 |
| 總表 215 | 低 | SSP 的 Word/Excel 兩張解析工作單表,新增規則寫成「一律允許」 | oscal.ssp_docx_parse_jobs、oscal.ssp_excel_parse_jobs(基線 02-schema.sql 兩條 *_insert ... WITH CHECK (true)) |
照 CM-2195 標準寫法新增 migration。⚠️ CM-2195 修的是 ap_docx/ar_xlsx 兩張,不是這兩張;CM-2209 文件寫「修正線已收」是錯的。主線 migration,回寫註明出貨基線待重產 |
| M06-16(#118 剩餘) | 低 | JobExecutionService 登記了但全庫沒人用,也沒權限檢查 |
di_containers/flow_engine/workflow_excution_containers.py:4,114-117 |
拆掉 import 與 provider(同檔 ElementVariableService 有人用,保留) |
現況:✅ 已修(CM-2216,commit a02409392,1.21.0 出貨)。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 184 | 低 | 開通這一步沒上鎖,連點兩次可能建出兩家公司 | app/setup/service/setup_wizard_service.py:37-41(註解宣稱有唯一約束,實際沒有)、:167、:249 |
決策者 09-26 裁加鎖:PostgreSQL advisory lock 包住「查開通+建立」,第二個請求回 409;錯誤註解改正;確認精靈前端收到 409 會顯示「已開通」而不是空白 |
現況:✅ 已修(CM-2217,commit 3ed47c7a9/套件 8ccfac73,1.21.0 出貨)。
決策者 09-26 裁:過期即唯讀、兩條縫都補。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 181 | 低 | 授權過期要等每天 UTC 02:00(台灣 10:00)排程跑過才轉唯讀;排程沒跑就一直可寫 | common/authz/license.py:280 viewer_is_readonly();排程 core/scheduler.py:275-323 |
讀照時用 compute_target_status(now, expires_at, expiry_policy) 當場算,取「存的」與「當場算的」較嚴者 |
| 總表 187 | 低 | 過期後還能產生代理程式註冊碼(/agents/ 整段豁免);問卷即時填答通道不經唯讀檢查 |
common/middleware/license_readonly_mw.py:77;套件 jedi-survey/jedi_survey/app/handler/fill_survey_socketio_handler.py:164 |
豁免收窄成代理程式回報結果那幾支(機器對機器保留);問卷即時通道補唯讀檢查 |
release note 要寫:授權到期那一刻起即唯讀,不再有「到期當天用到早上」的空窗。
現況:✅ 已修(CM-2218,commit a671d0b64,1.21.0 出貨)。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 190 | 低 | 授權連結可轉寄給別家的人代按,把對方的 Google 硬碟接進自己公司 | app/cloud_integration/service/google_drive_integration_service.py:95-99(產生 state)、:113-116(回呼只看 state) |
決策者 09-26 裁綁瀏覽器:發起時寫一個 HttpOnly cookie(值=state 的雜湊),回呼時比對。這是 OAuth 官方建議做法。換設備不受影響,只有「把連結轉給別人按」會失效 |
/static/ 公開路徑(中 1)現況:✅ 已修(CM-2219,commit 782ebb8b3,1.21.0 出貨)。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 185 | 中 | Flask 預設把 static/(全是使用者上傳檔)開成公開網址,開 8000 埠或換代理就整包不用登入可下載 |
core/app_factory.py:95-99(static_url_path='/static') |
static_url_path=None,static_folder 與寫入路徑不動 |
決策者 09-26 要求「確認過才可以關」,首腦已查:static/ 內只有使用者上傳檔(問卷答案、意見回饋附件、合規文件 Excel/PDF),沒有網頁用的圖片/CSS/JS;所有下載都走後端 API(send_file);BE、兩支會寫檔的套件(jedi-survey、jedi-file-upload)、FE 都沒有任何地方組 /static/... 網址;出貨 nginx(compliance-manager-fe/nginx.onprem.conf)只轉 /api/1.0 與 /socket.io,正式版本來就打不到。手測:問卷答案上傳下載、意見回饋附件、合規文件 Excel/PDF 匯出各一次,都要正常。release note 寫一句「/static/ 不再對外提供」。
現況:✅ 已修(CM-2220,commit 80dedfbb5/套件 fb271590,1.21.0 出貨)。
| 項次 | 嚴重度 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|---|
| 總表 218 | 低 | 沒有 AI 儀表板能力點的角色,直接打網址照樣能生成,每用一次付兩次 AI 費 | 套件 jedi-ai-dashboard/jedi_ai_dashboard/api/routes/ai_dashboard_route.py:103(只有 @require_license);主專案 core/plugins/ai_dashboard.py:52-61 |
AiDashboardAdapters 加 capability_required,生成端點掛 ai-dashboard.read |
| 總表 165 剩餘(#186) | 低 | 沒買問卷的客戶透過 AI 儀表板照樣查得到問卷 | di_containers/dashboard_apis/survey.py:20-45;套件 jedi_ai_dashboard/app/registry.py |
套件加「需要的模組」申報欄,兩支問卷查詢掛 survey |
兩件同一次發 jedi-ai-dashboard,追加到 CM-2197 發版清單。
現況:✅ 已修(CM-2221,1.21.0 出貨);掃描設定檔分享範圍與出貨基線的 SHARED 值域已隨基線重產帶上。
決策者 09-26 裁:照修。
| 事項 | 一句白話 | 在哪(修正線) | 怎麼修 |
|---|---|---|---|
| §7 第 13 項(兩處) | 權限檢查寫成「有裝檢查零件才檢查,沒裝就放行」。現在都有裝,但哪天組裝設定漏一行,檢查會悄悄消失 | ① 套件 jedi-compliance-audit/jedi_compliance_audit/app/service/review_service.py:41-42(任一零件是 None 就 return);② 主專案 app/oscal/service/export/ssp_export_app_service.py:74(if self._perm is not None:);③ 套件 jedi-task-platform/.../participant/app/service/task_assignee_service.py:99,178,214(if self._participant_role_service ...)逐處確認 |
沒接好就直接報錯(比照 jedi-task-platform/.../participant/common/guard.py:44 已經是 raise RuntimeError 的寫法)。⚠️ 開卡前 grep 一次:任務平台的守門殼已經是「拒絕執行」,第 62 項那支寫入已刪;清單以實查為準 |
| §7 第 18b 項/§3.2 第 28 項 | 「掃描設定檔管理」頁的「分享給子租戶」開關:新建時後端不認,要建好再編輯一次才生效 | 套件 jedi-detection/jedi_detection/app/service/detection_profile_service.py:897-901 _normalize_scope 只收 SYSTEM/TENANT |
補 SHARED 分支,建立與更新走同一套值域 |
| §3.2 第 29 項+§7 第 18b 項附帶 | 出貨用的資料庫結構還只認兩種值;新客戶只跑套件自帶腳本時,「分享給子租戶」可能變成別家也看得到 | 套件 jedi_detection/migrations/001-detection-tables.sql:176,203(CHECK)、002-detection-rls-grants.sql(沒有 SHARED);主專案鏡像 scripts/sql/packages/jedi_detection/ 同名兩支 |
兩支都補 SHARED(值域與「子租戶看得到母租戶分享」那條規則,照 FR-094 2026-09-14-fr094-cm1790-shared-scope-subtree.sql);出貨基線重產時帶上 |
現況:🗑️ 舊線已隨功能拆除、其餘已修(CM-2222,套件 87fd5439/BE ccc5795f6/前端 2537ea5;#89/#129~#132 另由 CM-2225~2227 修完,1.21.0 出貨)。
決策者 09-26 裁:CM-1849 不要再拖,一次做完。
jedi-evidence-classification/jedi_evidence_classification/api/routing.py 那組 legacy(:82、:96 兩段,:167 附近掛載),連同 FE 殘留(src/config/router/index.js 三條 :runFolderId 路由、src/config/api/api.js 舊十支常數、EvidenceClassificationService.js、AIEvidenceClassificationDialog.vue、useEvidenceClassificationJobs.js、cmmc_l1_aos.json)。完整清單見 docs/claude/memory/followup_fr107_remove_legacy_drive_classification_line.md。前提已查過:POC、STG 舊線資料皆 0 筆(見開頭第 1 點)。資料庫欄位 run_folder_id 與其 partial UNIQUE 這批不刪(刪欄位要另走 migration+基線,留下一版)。
SHARED 值域與規則、8-F 若有新增 migration。/static/ 不再對外提供(8-I);雲端硬碟授權要在同一個瀏覽器完成(8-H)。| 項次 | 狀態 | 理由 |
|---|---|---|
| 總表 213 | 🗑️ 已拆除(CM-2373,1.21.1;原標「不修、只記錄」,後改為整條頻道連同前端元件拔除) | 即時通知頻道不驗身分,但伺服器不往那裡送資料、前端元件 ProcessDiscussBox.vue 沒接回畫面。元件接回畫面前在 app/notification/handler/notification_socketio_handler.py:19,34,43 補身分驗證 |
| 總表 195 | 🚫 裁定不修 | 雲端硬碟通知註解說有去重、實際沒有;同步處理是冪等的,重複只是多跑一次 |
| 總表 193 | 🚫 裁定不修(決策者 10-01,原標「暫緩」) | 決策者 09-26:POC 階段暫緩(雲端資料夾分享要綁客戶 Workspace 網域,短期不綁) |
| #23/#24/#104 | ✅ 已修(#23 CM-2271+CM-2369;#24 補 12 張,餘 1 張屬平台層設定;#104 CM-2271,1.21.0/1.21.1;原標「暫緩」) | 第 6 批「資料庫最後一道牆」,程式面先修、測過一版、決策者裁「開牆」才開卡 |
| #105 | 🕓 SaaS 前必做(仍是) | SaaS 上線前必做 |
| #98/#99/#91/#130 | #98/#91 🚫 裁定不修;#99 📋 已裁記錄不修(交付首位客戶前改只認正式公鑰);#130 ✅ 已修(CM-2061 驗證、CM-2223) | 各自已有裁定(見 CM-2209 文件第 6 節) |
| 總表 §7 第 8 項(日誌表隔離) | 已裁、不修程式 | 決策者 09-26:系統日誌、API 日誌定位為「只給原廠維運看的全系統資料」,不做客戶隔離(畫面上本來就只有平台管理員看得到,core/plugins/api_log.py 走 platform-admin 軸)。要做的只是把這個定位寫進設計文件 |
| 總表 §7 第 14 項(SSP 功能權限) | 已裁、不修 | 決策者 09-26:專案 SSP 維持看專案角色(管理者可改、成員只能看),不另加功能權限;資源庫範本 SSP 看合規資源庫權限(第 7 批已補齊) |
| 總表 §7 第 18 項(GitHub 附件) | 暫緩(決策者 09-26 裁先不用,SUMMARY 無對應條目,查不到後續) | 決策者 09-26:先不用 |
| 總表 §7 第 5 項(雲端硬碟通知網址沒掛登入) | 結案 | 由 Google 呼叫、靠頻道憑證擋;衍生兩條低風險即總表 195(不修)/196(8-C) |
| 總表 207、216、191 的平台管理員那一半 | 已修 | 207 由 CM-2111(套件 e12287e2);216 由 CM-2171;191 見 8-A |
docs/security-report/ 只回寫第 7 批,第 1~6 批修好的還寫未修(例:M05 第 1~4 條,CM-2034 已 Done)。修正線那份是對的,合回時以修正線為準,再補第 146~198 件與第 7 批以後的狀態。沿革見 docs/features/FR-075-2609-jedi-package-security-audit/handoff/security-scan-LOG.md 與 git log。