FR-120 交修正線清單——第 8 批(掃描線全案收口,給 FR-114 首腦)

現況(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)。以下內文保留當時的分類過程。

交修正線清單:第 8 批

掃描線全案收口後,所有還沒修的項目經決策者 2026-09-26 逐項裁定,整理成這份交 FR-114 開第 8 批。 分類底稿:同目錄 remaining-classification.md(CM-2209)。檔:行已在修正線(BE 1516d90bc、套件 e758cd6a)核過;行號會漂,開卡前 grep 一次。

§1

這份給誰、怎麼用

讀者:FR-114 首腦。決策者已經全部裁完,這份裡沒有要再問的,照著開卡即可。

  • 第一段:要修的,按同一套修法分成 12 組,每組建議開一張卡。
  • 第二段:卡上的特別注意事項(發版、出貨基線、release note)。
  • 第三段:不修、暫緩、已修的,列出來讓你知道不要派。
  • 第四段:這份整理時順手核出的三份紀錄不一致,合回報告時要改。

幾個詞:守門=程式裡檢查「你有沒有資格做這件事」的那段;修正線=fix/security-b1 工作區;出貨基線=新客戶安裝時拿到的資料庫結構(scripts/init/02-schema.sql)。

🔴 開卡前先看這三件:

  1. 8-L「舊線退場」可以直接刪,不用等客戶確認:首腦 09-26 唯讀查過,POC(189)與 STG(188)的 compliance.evidence_classification_runs 都是 0 筆舊線資料(run_folder_id IS NOT NULL)。原本 T-6.1 保留舊路由的理由(POC 可能有客戶舊結果)已不成立。DEV 有 8 筆測試資料,刪路由後那 8 筆打不開屬預期。
  2. 要多發一支套件 jedi-ai-dashboard(8-J),它原本不在 CM-2197 發版清單。
  3. 出貨基線要帶兩件:8-K 的 SHARED 值域、8-E 第 215 項兩張表的新增規則。都追加到 CM-2197。

§2

第一段:要修的(12 組)

8-A 補歸屬/成員檢查(中 1、低 4)

現況:✅ 已修(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

8-B 診斷包與紀錄遮罩(中 3、低 1,一張卡一起修)

現況:✅ 已修(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='值' 寫法要在本卡補進規則。

8-C 輸出前跳脫與安全寫法(中 1、低 4)

現況:✅ 已修(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

8-D 維運腳本與診斷包路徑(中 1、低 2)

現況:✅ 已修(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 兩邊統一轉成帶時區

8-E 零散小修(低 3,可併一張)

現況:✅ 已修(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 有人用,保留)

8-F 首次安裝精靈加鎖(低 1)

現況:✅ 已修(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 會顯示「已開通」而不是空白

8-G 授權過期的唯讀要即時且沒有縫(低 2)

現況:✅ 已修(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 要寫:授權到期那一刻起即唯讀,不再有「到期當天用到早上」的空窗。

8-H 雲端硬碟授權綁發起的瀏覽器(低 1)

現況:✅ 已修(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 官方建議做法。換設備不受影響,只有「把連結轉給別人按」會失效

8-I 關掉 /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/ 不再對外提供」。

8-J AI 儀表板補權限(低 2,要發 jedi-ai-dashboard)

現況:✅ 已修(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 發版清單。

8-K 「沒接好就放行」改「沒接好就拒絕」+掃描設定檔分享範圍(總表 §7 第 13、18b 項)

現況:✅ 已修(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);出貨基線重產時帶上

8-L 證據分類舊線退場(高 1、中 2)+把 CM-1849 做完

現況:🗑️ 舊線已隨功能拆除、其餘已修(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+基線,留下一版)。
    • 一次消掉:#9(高)舊線預覽能抓任何 Google 檔、#66(中)舊線查詢不檢查成員、#67(中)舊線搜尋條件字串接。
  • CM-1871(T-6.4):分類容器 image 進出貨包,CM-1849 唯一沒做的子卡。
  • CM-2061 驗證卡(等舊線拆完才派):確認 #89(證據內容指揮 AI)、#131(壓縮檔吃光記憶體+殘留程序)、#132(容器六個套件沒鎖版本)、#129(刪整批殘留)是否還在;還在就開修正。決策者先前已裁:#89 只做事前預防、#132 鎖版本加校驗碼不能省、#131 現在修、#130 可以緩。

§3

第二段:卡上的注意事項

  1. 追加到 CM-2197 發版卡:jedi-ai-dashboard(8-J,新增);jedi-detection(8-K);jedi-evidence-classification(8-L);jedi-task-platform/jedi-compliance-audit/jedi-survey 若 8-A/8-G/8-K 有改到。
  2. 出貨基線重產時要帶:8-E 第 215 項 migration、8-K 的 SHARED 值域與規則、8-F 若有新增 migration。
  3. release note 要寫三句:授權到期即唯讀(8-G);/static/ 不再對外提供(8-I);雲端硬碟授權要在同一個瀏覽器完成(8-H)。
  4. 要實裝測一次:8-D 改安裝指令稿、8-F 改開通流程、8-L 動出貨包。

§4

第三段:不要派的

項次 狀態 理由
總表 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

§5

第四段:三份紀錄不一致(合回報告時要改)

  1. 主線 docs/security-report/ 只回寫第 7 批,第 1~6 批修好的還寫未修(例:M05 第 1~4 條,CM-2034 已 Done)。修正線那份是對的,合回時以修正線為準,再補第 146~198 件與第 7 批以後的狀態。
  2. 總表第 181~218 項從沒進 PM 報告。掃描線在第 8 批出包後回寫(等你回我「b3 實際修掉的項次+commit」)。
  3. CM-2209 分類文件兩處錯誤:第 191 項、第 215 項都寫「修正線已收」,實際都還沒修(見 8-A、8-E)。

沿革見 docs/features/FR-075-2609-jedi-package-security-audit/handoff/security-scan-LOG.md 與 git log。