U11 檢查結果:系統診斷包的資料收集器

U11 檢查結果:系統診斷包的資料收集器

檢查日期 2026-09-25|對應卡片 CM-2163(母卡 CM-2152)|檢查範圍 7 個檔案 1,548 行|工具 run ID wf_408b5225-5ee

§1

🔴 一句話結論

收集器取主機資料的 docker 指令都是寫死的,資料庫讀取也只看兩張紀錄表,這兩件沒問題。問題出在「收進包之前遮得乾不乾淨」和「指令版在主機上用的暫存資料夾」。

工具正式清單 2 條,三人面板都是 3:0 通過,兩條都是中:

  1. (中)寄信失敗時,寄信伺服器的密碼會以 password='明文' 的寫法進日誌,診斷包原樣帶走。 遮罩只認 JSON 的 "password":"值" 和 password: 值 兩種寫法,不認這一種。我實測確認兩支遮罩都漏。
  2. (中)指令版 sudo guidant diag 在「容器使用者寫得動的資料夾」裡,用一個猜得到的名字建暫存資料夾,而且不檢查那是不是捷徑(符號連結)。 已經在容器裡拿到一般權限的人可以預先放捷徑,讓主機的最高權限帳號把檔案寫到別的地方去。我在自己的暫存資料夾裡照同樣手法重現成功。

我照卡片逐支開檔,另外找到 3 條(未經三人面板投票):

  1. (中)畫面版的設定快照遇到跨多行的值,只遮第一行。 資料庫密鑰 JSON 的第二行、私鑰檔的內容會原樣進包。
  2. (低)預蒐模式讀檔時,完全照索引檔寫的路徑去讀,沒限制在暫存資料夾裡。 這一條是第 2 條在容器內的那一半。工具把它併進第 2 條,這裡單獨列出來,是因為它要改的是另一支檔。
  3. (低)存取紀錄的「網址」欄完全沒過遮罩。 網址裡帶權杖參數(?access_token=…)時會原樣進包。DEV 查到 1 筆,是測試資料。

不重報的:容器紀錄完全沒過遮罩(總表第 173 項已登記,即 U2-2)。這一棒順帶確認,指令版的「預蒐模式」同樣沒過遮罩,兩條路是同一個洞,修的時候要一起修(見下方疑點 ①)。

§2

這一棒在檢查什麼

「系統診斷包」是客戶系統出問題時,把整台機器的現場打成一個壓縮檔寄給原廠分析用的。這個包不加密,會經過客戶的電腦、郵件或隨身碟、原廠的電腦,最後被貼進 AI 對話。所以包裡的密碼有沒有遮乾淨,就是這個功能唯一的防線。

U10 查的是「誰能按下產包」和「組裝流程」,這一棒 U11 查的是真正去拿資料的那七支程式:它們去哪裡拿、拿的時候怎麼組指令、拿到後有沒有遮。

檔案 行數 做什麼
infra/support/collector/host_collector.py 201 開發機/原生部署用:直接跑 docker ps、docker logs、df,讀設定檔
infra/support/collector/staged_collector.py 178 出貨主機用:主機端的腳本先把資料存進暫存資料夾,這支再讀進來
infra/support/collector/container_collector.py 105 畫面版用:在容器裡面,拿不到 docker 就誠實寫「取不到」,設定改讀當下的環境變數
infra/support/diag_db_reader.py 242 讀資料庫的存取紀錄、錯誤紀錄、改版水位、各表筆數
infra/support/diag_log_reader.py 176 依時間範圍切應用日誌檔
infra/support/diag_event_fetcher.py 303 從錯誤收集站撈錯誤清單
infra/support/diag_packer.py 343 全部打成 tar.gz,超過大小就從最舊的開始砍
§3

掃到什麼(總覽)

# 這是什麼問題 出事會怎樣 要先有什麼才打得到 該補檢查的位置 嚴重度+為什麼 來源
U11-1 遮罩不認得 password='值' 這種寫法,而寄信套件寄信失敗時就是這樣把整組寄信設定寫進日誌的 客戶的寄信伺服器帳號密碼跟著診斷包寄到原廠、貼進 AI 對話;包裡的說明檔還寫著「密碼都已遮罩」 客戶有設寄信帳密,時間範圍內寄信失敗過一次(封閉網路很常見),然後有人產診斷包。不需要攻擊 遮罩規則 infra/support/diag_masking.py:164-169(補認 名稱=值、名稱='值');資料庫紀錄改走完整日誌遮罩 infra/support/diag_db_reader.py:237;源頭在寄信套件 jedi_notification/infra/smtp_mail/smtp_mail_adapter.py:52、:57 🟠 中:正常維運就會發生,但外洩對象是拿到包的人,不是任意網路使用者 工具(面板 3:0)
U11-2 指令版在容器寫得動的資料夾裡,用猜得到的名字建暫存資料夾,不檢查是不是捷徑 已經在容器裡拿到一般權限的人,可以讓主機最高權限帳號改掉主機上任意檔案的權限,或把內容寫進去 先在容器裡拿到一般使用者的執行權(要另一個漏洞),而且主機管理員之後跑了 sudo guidant diag scripts/installer/guidant:700-706(改用 mktemp -d 建在只有 root 能寫的地方;或先檢查路徑不存在、不是捷徑) 🟠 中:後果是從容器跨到主機,但要先有另一個漏洞,還要等管理員跑診斷 工具(面板 3:0)
U11-3 畫面版的設定快照遇到跨多行的值,只遮第一行 資料庫密鑰 JSON 的第二行、私鑰檔的內容(如果環境變數直接放內容而不是路徑)原樣進包 平台管理員從畫面產包,而且當下的環境變數裡有跨多行的機密值 infra/support/collector/container_collector.py:94(不要把環境變數串成 名稱=值 的文字再遮,改成逐個判斷名稱) 🟠 中:正常產包就會發生,前提是有多行機密值;出貨設定檔裡的 DB_SECRET 是單行,所以今天的落地版沒中 runner 實測(未經三人面板)
U11-4 預蒐模式讀檔時,完全照索引檔寫的路徑去讀,沒限制在暫存資料夾裡 能改索引檔的人,可以讓容器內用最高權限跑的打包程式把容器裡任何檔案讀進包 要能寫暫存資料夾,而這其實就是 U11-2 的前提 infra/support/collector/staged_collector.py:90(取實際路徑後,確認還在 staging_dir 底下);:140(服務名稱也要驗,不然包內檔名會出現 ../) 🟢 低:前提跟 U11-2 相同,後果比它小 runner 實測(未經三人面板;工具在 U11-2 裡提到這一半)
U11-5 存取紀錄的「網址」欄完全不遮 網址裡帶的權杖參數原樣進包 有人用網址參數傳權杖(本產品的正常端點不這樣做),加上有人產包 domain/support/entity/diag_bundle.py:30(MASKED_API_LOG_COLUMNS 補上 url);遮罩也要認得網址參數 🟢 低:產品本身不用網址傳權杖,DEV 只有 1 筆測試資料 runner 開檔+DEV 查證(未經三人面板)

現況(2026-10-01):本棒各條後來的處理結果如下(過程紀錄保留,不改)。

  • U11-1(遮罩不認 password='值')=總表第 207 項,✅ 已修(寄信套件 CM-2111;遮罩規則 CM-2212,1.21.0 出貨)。
  • U11-2(診斷指令暫存資料夾)=總表第 208 項,✅ 已修(CM-2214,commit d39181f3b/046553756,1.21.0 出貨)。
  • U11-3(設定快照多行只遮第一行)=總表第 209 項,✅ 已修(CM-2212,1.21.0 出貨)。
  • U11-4(預蒐模式路徑未限制)=總表第 210 項,✅ 已修(CM-2214,1.21.0 出貨)。
  • U11-5(網址欄不遮)=總表第 211 項,✅ 已修(CM-2212,1.21.0 出貨)。
§4

工具報的逐條

工具派了一位研究員讀整個範圍,另一位專找寫死在程式裡的密碼金鑰。第一位研究員跑了約 90 分鐘被中斷,工具自動重派一次,這次跑完。兩個候選都送進三人面板,6 票全投完,兩條都是 3:0 通過。

U11-1(工具 F1)— 寄信密碼以 password='值' 寫法進日誌,遮罩漏掉(中)

  • 嚴重度:🟠 中(面板三票都判中)
  • 該補檢查的位置:
    • 遮罩規則:infra/support/diag_masking.py:164-169(日誌那一道),要補認 名稱=值 和 名稱='值'
    • 資料庫紀錄只走最弱的那道:infra/support/diag_db_reader.py:237
    • 源頭(套件,範圍外):jedi_notification/infra/smtp_mail/smtp_mail_adapter.py:52、:57
  • 白話說明:寄信套件寄信失敗時,會把「寄信設定」整包印進錯誤日誌:Error sending email smtp info: … username='u' password='明文' …。這個寫法是 Python 印物件的預設格式。診斷包的遮罩只認兩種寫法:JSON 的 "password":"值",和日誌裡的 password: 值,不認 password='值'。所以這行會原樣進 logs/app.log.slice,也會進 db/system_logs.csv。
  • 我自己核對(開檔+實測):
    • 開檔確認寄信套件 smtp_mail_adapter.py:52、:57 真的是 logger.error(f"... smtp info: {self.config}")。設定物件的 password 是一般字串(smtp_email_config_dto.py:13),不是會自動隱藏的密碼型別。
    • 主專案 app/notification/service/notification_service.py:67 把資料庫裡存的寄信密碼放進這個欄位。
    • 用真的設定物件造一行假日誌丟進兩支遮罩:mask_json_like 和 mask_log_lines 都原樣留下假密碼。
    • DEV 唯讀查證(2026-09-25 18:10 +08):system_logs 與本機 log/app.log* 目前都沒有 smtp info 這一行,因為 DEV 沒有寄信失敗過。所以這只證明「一失敗就會外洩」,不代表 DEV 已經外洩。
  • 與既有項目的關係:
    • CM-1606(FR-078 N1)已經登記「寄信套件把密碼寫進日誌」,那是源頭。
    • 這一條是下游:就算源頭沒修,診斷包也不該把它帶出去。
    • U10-1 已經報過「遮罩認得的寫法太少、資料庫紀錄走最弱那支」,並列了 名稱=值 的缺口。這一條是那個缺口的第一個確認的真實來源。建議首腦判斷要併進 U10-1(與第 162 項一起),還是單獨一條。
  • 建議修法:遮罩補認 名稱=值 和 名稱='值'(鍵名清單沿用同一份);資料庫紀錄改走 mask_log_lines。寄信套件那半(不要印整個設定,或把密碼改成隱藏型別)照外部套件異動規範先提醒、決策者點頭才動。

U11-2(工具 F2)— 指令版在容器寫得動的資料夾裡建暫存資料夾,跟著捷徑走(中)

  • 嚴重度:🟠 中(面板三票都判中)
  • 該補檢查的位置:scripts/installer/guidant:700-706(範圍外,但資料是流進本範圍的 staged_collector.py)
  • 白話說明:
    • 出貨主機上的 sudo guidant diag 會以主機最高權限(root)建一個暫存資料夾,路徑是 /srv/guidant-ai/home/.diag-stage-<程序編號>,然後往裡面寫檔、改權限。
    • 問題是 home 這個資料夾同時掛進容器、而且屬於容器裡的一般使用者(uid 1000),所以容器裡的程式也寫得動它。
    • 程序編號猜得到。容器裡的人可以預先放一個同名的「捷徑」(符號連結)指到主機別的地方,主機的 root 跑診斷時不檢查就跟著捷徑走,改權限、寫檔都落到那個地方。
  • 我自己核對:
    • 開檔確認 guidant:700 路徑的組法、:705-706 的 mkdir -p 和 chmod 700、之後的 > 寫檔與 cp,一路都沒檢查是不是捷徑。
    • 出貨 compose docker/production/docker-compose.yml:152 把 home 掛進容器;install.sh:1319 和 entrypoint 把它設成 uid 1000 所有。
    • 在自己的暫存資料夾照同樣手法重現:先放捷徑,再用腳本同樣的 mkdir -p、chmod、> 寫檔 → 權限改到捷徑指的資料夾,檔案內容也寫進捷徑指的檔案。
    • 打折處:沒有在真的出貨主機上跑,是照腳本的指令在本機資料夾重現。
  • 前提與為什麼是中:攻擊者要先在容器裡拿到一般使用者的執行權,這要靠另一個漏洞;還要等主機管理員跑診斷。但得手後是從容器跨到主機,這正是容器隔離要擋的事。
  • 建議修法:暫存資料夾改用 mktemp -d 建在只有 root 能寫的地方,再用唯讀方式掛給容器;至少先檢查路徑不存在、也不是捷徑。容器內的打包程式改用 uid 1000 跑(docker exec -u 1000),除非真的需要 root。
§5

卡片點名的疑點逐條回答

① 每一類收集物在打包前有沒有過遮罩?——⚠️ 大部分有,兩類沒有 → 成立(U11-1、U11-3、U11-5,另有第 173 項)

逐支開檔核對的結果:

收集物 從哪支來 打包前的遮罩 結論
容器狀態(docker ps)、資源用量、磁碟 三支收集器 沒有 不需要:內容是容器名稱、狀態、用量,不含機密
設定檔(指令版) host_collector.py:197、staged_collector.py:174 mask_env_text 有遮,但規則窄(見 U10-1)
設定快照(畫面版) container_collector.py:94-95 mask_env_text 有遮,但跨多行的值只遮第一行 → U11-3
容器紀錄(開發機直接收) host_collector.py:136-156 沒有 總表第 173 項(U2-2),不重報
容器紀錄(出貨主機預蒐) staged_collector.py:128-153 沒有 同一個洞的另一條路。實測:假權杖三種寫法全部原樣留下、遮罩清單空白。修第 173 項時這支要一起改
應用日誌 diag_log_reader.py:152 mask_log_lines 有遮,但不認 名稱=值、名稱='值' → U11-1
存取紀錄、錯誤紀錄(資料庫) diag_db_reader.py:237 mask_json_like(最弱) 只遮四個欄位;url 欄沒遮 → U11-5
錯誤收集站事件 diag_event_fetcher.py:275-287 mask_structure 有遮;欄位名稱像密碼的整個換掉
各表筆數、改版水位、分區 diag_db_reader.py:175-222 不需要 只有數字與版號

② 遮罩規則認不認得 KEY=值/Bearer/連線字串?——❌ 認得的不夠 → 成立(併入 U10-1,新增一個真實來源 U11-1)

我寫了一支小程式,拿假密碼逐一丟進三支遮罩。跟 U10 的實測結果一致,另外補了三種:

寫法 設定檔遮罩 日誌遮罩 資料庫紀錄遮罩
password='值'(寄信套件的真實寫法) — ❌ ❌
Authorization: Bearer … — ✅ ❌
行中間的 DB_PASSWORD=值 — ❌ ❌
postgresql://帳號:密碼@主機、redis://:密碼@主機 ❌ ❌ ❌
SMTP_PASS=值、JWT=值(名稱不含 password/secret/token/key) ❌ — —
{'password': '值'}(單引號字典) — ❌ ❌
跨多行的值(第二行起) ❌ — —

設定檔的部分:出貨設定檔裡真的放機密的欄位(資料庫、Redis、S3、JWT、加密金鑰、AI 金鑰)名稱全部含 password/secret/key,都遮得到,今天出貨的設定檔本身不會外洩(U10 已實測,本棒再以 install.sh 寫出的欄位名單核對一次)。問題在日誌與資料庫紀錄裡混進來的機密。

③ 讀主機檔案、跑 docker 指令時,路徑與參數是寫死的還是拼進來的?——✅ 指令寫死;⚠️ 預蒐讀檔的路徑是拼進來的 → 部分成立(U11-2、U11-4)

  • docker 指令(host_collector.py):docker ps、docker stats、docker logs、df、du 全部用清單形式呼叫(不經過 shell),服務名稱來自檔案裡寫死的清單 KNOWN_SERVICES,時間參數是程式算出來的時間字串。沒有任何外部輸入進得了指令。不成立。
  • 設定檔路徑:host_collector.py:68 是 資料目錄/guidant.env,資料目錄來自指令參數 --data-dir,只有能在主機下指令的人才給得了。不成立。
  • 應用日誌:diag_log_reader.py:85-100 只列出日誌資料夾裡、檔名以 app.log. 開頭的檔,路徑來自日誌設定。不成立。
  • 預蒐模式讀檔(staged_collector.py:90):staging_dir / 索引檔裡寫的檔名,沒檢查是否跑出暫存資料夾。實測:索引檔寫 ../outside/secret.txt,就把暫存資料夾外面的檔讀進包;服務名稱寫 ../../evil,包內檔名就變成 logs/docker-../../evil.log。→ 成立(U11-4),前提是能寫暫存資料夾,也就是 U11-2 的前提。
  • 錯誤收集站網址:diag_event_fetcher.py:71-93 來自環境變數,不是使用者輸入。下一頁的網址取自對方回傳的 Link 標頭,最多 10 頁、每次 10 秒逾時,而且跳去別的主機時 Python 會把權杖標頭一起帶過去。但要做到這一步得先控制錯誤收集站本身,所以不列。

④ 資料庫讀取器用什麼身分讀?會不會把全租戶資料撈進包?——⚠️ 會看全部,但這是設計 → 不成立

  • 連線用的是應用程式本身的資料庫帳號(出貨版是 cm_app,install.sh:1386),每次查詢前設 SET LOCAL app.is_super_admin = 't'(diag_db_reader.py:63)。
  • 查的四樣東西裡,只有兩張紀錄表有內容:api_logs、system_logs。DEV 唯讀查證(2026-09-25 18:10 +08)這兩張表都沒有客戶欄、也沒開資料庫隔離(relrowsecurity=false),本來就是整台機器共用的紀錄。另外兩樣是改版水位,和各表筆數(估計值,只有數字)。
  • 結論:會把所有客戶的操作紀錄帶進包,但診斷包的用途就是「整台機器的現場」,而產包的兩個入口已由 U10 確認只有平台管理員和主機 root 用得到。不成立。
  • 每張表最多 20 萬列(:45),查詢的表名與欄名是檔案裡寫死的常數,值都走參數綁定,沒有注入的空間。

⑤ 打包的檔名與壓縮大小上限?——✅ 有上限 → 不成立

  • 整包預設 100MB(domain/support/entity/diag_bundle.py:21),用未壓縮大小的 3 倍當預算先砍,寫完再以實際大小核對,還超過就寫進包裡的說明檔(diag_packer.py:163-181)。
  • 各層還有自己的上限:日誌切片 40MB、每張表 20 萬列、每個容器 5,000 行、錯誤事件 10 頁×100 筆。
  • 包內檔名來自程式裡寫死的字串。只有預蒐模式的服務名稱是從索引檔拼進來的 → 已列在 U11-4。
  • 包內每個檔權限 0600(:203),不是還原到別人機器時才要擔心的那種路徑。
  • 指令版可以用 --no-limit 關掉上限,但那要主機 root,不算漏洞。

⑥ 「有人守了一半」八種樣式——除 ① 的遮罩外不成立

樣式 結論
只驗身分、不驗資料歸屬 不適用:收集器不做守門,守門在 U10 的入口,已確認只有平台管理員/主機 root
列表有查、單筆沒查 不適用
守門寫在網址層,第二支路由沒掛 不適用:收集器沒有路由
守門條件用 or 串起來 不適用
「查不到」和「沒權限」混在一起 不適用
背景或系統身分執行時,假設呼叫者一定是自己人 成立一半:預蒐模式假設「暫存資料夾裡的東西一定是主機端腳本放的」,所以照索引檔讀檔(U11-4)。但那個資料夾容器使用者也寫得動(U11-2)
防重放、計次只在單一進程內有效 不適用
註解說這裡刻意不檢查,上一層卻沒檢查 成立一種變形:diag_masking.py:26-28 寫「四條路徑共用同一份判準,不分岔」,但資料庫紀錄只走最弱那道、容器紀錄一道都沒走(U10-1、第 173 項、U11-1)
§6

逐條細節(runner 自行發現,未經三人面板投票)

U11-3 — 畫面版設定快照遇到跨多行的值只遮第一行(中)

  • 嚴重度:🟠 中

  • 該補檢查的位置:infra/support/collector/container_collector.py:94

  • 白話說明:畫面版在容器裡拿不到設定檔,改讀「當下生效的環境變數」,做法是把每個變數串成 名稱=值 一行一個,再用設定檔那支遮罩去遮。遮罩是一行一行比對的。如果某個值本身跨好幾行,只有第一行開頭是 名稱=,會被遮到;後面幾行看起來只是普通文字,原樣留下。

  • 實測:造一組假環境變數丟進去:

    • 跨兩行的 DB_SECRET JSON → 第二行的假密碼留下
    • 私鑰內容跨三行的 AGENT_JWT_PRIVATE_KEY → 中間那行留下
    • CELERY_BROKER_URL=redis://:假密碼@… → 名稱不像密碼,整行留下
    • REDIS_SECRET(單行)、SENTRY_DSN、AI 金鑰 → 遮掉

    更麻煩的是,遮罩清單會列出 DB_SECRET、AGENT_JWT_PRIVATE_KEY「已遮罩」,讀包的人會以為它們遮乾淨了。

  • 影響:今天的落地版不會中。install.sh 寫出的 DB_SECRET、REDIS_SECRET 是單行;AGENT_*_KEY 放的是檔案路徑,不是內容。但只要部署端把機密以多行值或連線網址放進環境變數,就會原樣進包。 我沒有在 DEV 或出貨設定裡找到這種現況。

  • 建議修法:不要先串成文字再遮。直接逐個看環境變數的名稱,像密碼就整個值換成 ***;值裡有 ://帳號:密碼@ 的也遮。

U11-4 — 預蒐模式讀檔不限制在暫存資料夾內(低)

  • 嚴重度:🟢 低
  • 該補檢查的位置:infra/support/collector/staged_collector.py:90(讀檔路徑)、:140(包內檔名用的服務名稱)
  • 白話說明:指令版的流程是主機端腳本先把資料存進暫存資料夾,再附一份索引檔 staged.json 說明每個檔是什麼。容器裡的打包程式照索引檔寫的檔名去讀,但沒有檢查檔名裡有沒有 ../ 這種「往上一層」的寫法。
  • 實測:造一份假索引檔,file 寫成 ../outside/secret.txt → 把暫存資料夾外面的檔讀進包,而且因為被歸類成「容器狀態」,完全沒過遮罩;service 寫成 ../../evil → 包內檔名出現 logs/docker-../../evil.log。
  • 影響:打包程式在容器裡用 root 執行(docker exec 沒指定使用者、映像檔也沒設 USER),所以讀得到容器裡任何檔案。
  • 前提與為什麼是低:要能改索引檔,而那個資料夾只有主機 root 和容器使用者寫得動。能做到的人已經符合 U11-2 的前提,U11-2 的後果更大。修 U11-2 時順手改這支即可。
  • 建議修法:取實際路徑後確認還在 staging_dir 底下,不在就回「取不到」;服務名稱只允許 KNOWN_SERVICES 裡的名字。

U11-5 — 存取紀錄的「網址」欄不遮(低)

  • 嚴重度:🟢 低
  • 該補檢查的位置:domain/support/entity/diag_bundle.py:30(MASKED_API_LOG_COLUMNS 只有 params、request、response、message)
  • 白話說明:存取紀錄有一欄 url 存完整網址(含 ? 後面的參數,common/middleware/app_mw.py:188)。這欄不在遮罩名單裡,就算在,現在的遮罩也不認網址參數的寫法(?token=值)。
  • DEV 查證(2026-09-25 18:10 +08,唯讀):api_logs 約 2 萬筆裡有 895 筆網址帶參數;名稱像權杖/密鑰的只有 1 筆 ?access_token=qs-…,看起來是測試打的。Google 雲端硬碟回呼帶的 code= 參數目前 0 筆。
  • 前提與為什麼是低:本產品正常的 API 不用網址參數傳權杖(登入權杖走標頭),唯一會在網址帶一次性代碼的是 Google 回呼,而那個代碼一用就失效。
  • 建議修法:url 加進遮罩欄位名單,遮罩補認網址參數。和 U10-1 一起改。
§7

這份結果可信到什麼程度

第一層:工具正式報告(經三人面板驗證)

  • 驗證章:verified(stamp CLAUDE-SECURITY-REVISION-1bafa3bfe2e7-dirty.json)
  • 候選 2、面板 6 票(2 條都是 3:0 通過)、研究員派出 2/交回 2、failed 0、續跑 0、沒有遺失的候選。
  • 第一位研究員跑約 90 分鐘被中斷,工具自動重派一次(journal 顯示 research:repository:all 啟動兩次),failed 計數仍是 0。
  • 第 2 條的主要位置在範圍外的安裝腳本,是研究員順著資料流追出去的。
  • 兩條我都自己開檔核對屬實,也都各自實測過(第 1 條用真的設定物件丟進遮罩;第 2 條在自己的資料夾照同樣指令重現)。

第二層:runner 自行開檔核對+實測(未經三人面板投票)

  • 範圍 7 支逐支通讀;卡片「重點看什麼」五條,加上派工要求的四問、「有人守了一半」八種樣式,逐條答完。
  • 跨讀的範圍外程式(只讀不報):infra/support/diag_masking.py、scripts/installer/guidant 的 diag 段、install.sh 寫設定檔那段、出貨版 compose、Dockerfile、entrypoint、app/support/diag_cli.py、打包核心、寄信套件的 adapter 與設定物件。
  • 實測:
    1. 三支遮罩 × 十幾種寫法
    2. 容器收集器的多行值與網址帳密
    3. 預蒐收集器的 ../ 路徑與容器紀錄遮罩
    4. 暫存資料夾的捷徑(在本機暫存區照腳本指令重現)
    5. 寄信設定物件的真實日誌寫法
  • DEV 資料庫唯讀查證(2026-09-25 約 16:40 與 18:10 +08,只下 SELECT):兩張紀錄表的隔離設定、system_logs 的密碼形狀(10 筆都是堆疊裡印出的程式碼、值是變數名)、smtp info 筆數(0)、api_logs 網址參數。
  • 打折處:
    • U11-2 沒在真的出貨主機上跑,是在本機照腳本同樣的指令重現。
    • U11-1 在 DEV 沒有實際外洩的紀錄(DEV 沒寄信失敗過),結論來自直接呼叫遮罩函式。
    • 沒有起完整服務產真包。U10 已經產過一包(走降級路徑),本棒沒有重做。
§8

執行概況

項目 值
掃描目標 BE repo compliance-manager-be,branch feature/review
版本 1bafa3bfe(工作區有平行線未 commit 改動,範圍 7 支檔案本身無改動)
工具 Claude Code 官方 claude-security plugin 0.11.0
參數 mode scan/effort low/focus attack-surface/scope 7 檔
run ID wf_408b5225-5ee
報告目錄 CLAUDE-SECURITY-20260925-082706/(不入版控)
耗時 約 181 分鐘(10,858 秒,含第一位研究員被中斷後重派)
研究員 2 派出/2 交回(全範圍 1+密碼金鑰專掃 1;全範圍那位被中斷後重派 1 次),failed 0
候選/面板票 2/6(兩條都是 3:0 通過)
驗證章 verified
工具發現 2 條(中 2)
runner 自行發現 3 條(中 1、低 2),皆未經面板