本卡屬 FR-188(母卡 CM-3728),修 FR-187 資安掃描發現的 #241(中,FR-187 A1、A2 兩棒各 3:0)。嚴重度:中。發現原文、檔名行號、面板票數在
docs/features/FR-187-2611-post-fr172-security-scan/reports/(工作坊工作區compliance-manager-be/.worktrees/CM-3711/裡,主線還沒合;總表docs/features/security-scan-consolidated/README.md§3.1 同樣在那裡)。Stage 未排,由排批的人決定(見下方「排批注意」)。
管理員在「遠端 Agent → 工具帳密」設給 Agent 的檢測工具帳密(SSH、LDAP、SonarQube 等),真正存放的地方是 Agent 端,但送過去的途中會經過主系統資料庫:長輪詢通道下主系統不能直接推給 Agent,只能先寫一列進 compliance.agent_requests(信箱),等 Agent 來拿。
問題:①寫進信箱時 payload 是明文帳密;②Agent 收走、回報 done 之後,payload 不清;③沒有任何程式刪這張表。資料庫備份或匯出一流出去,所有設過的受檢主機帳密都在裡面。違反 .claude/rules/security/secrets.md「解密後的帳密只留記憶體:派工單不含明文」。
為什麼不能「只放記憶體不進資料庫」:主系統跑多個 gunicorn worker,管理員送帳密的請求與 Agent 的長輪詢常落在不同 worker,記憶體不共用。所以要進資料庫,但進之前加密、用完清空。
/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/app/remote_agent/service/agent_request_service.py:200-207 _new_row:payload=dict(payload) 原樣寫入
/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/app/remote_agent/service/agent_request_service.py:217-232 reply:只改 status/result,不清 payload
/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/infra/remote_agent/command_sources_impl.py:28-37 requests_for:交給 Agent 時讀 r.payload
/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/infra/remote_agent/repository/agent_request_repo_impl.py:49-70 transition/expire_due:只改狀態
/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/infra/remote_agent/agent_credential_client.py:33/42 帳密從這裡進 ask(credentials_set)
/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/infra/cloud_integration/crypto/fernet_crypto.py 既有加密工具,APP_ENCRYPTION_KEY(reuse)
行號以 2026-11-09 主線為準,對不上就以內容為準。
infra/cloud_integration/crypto/fernet_crypto.py,用法見 app/system_config/service/ai_provider_key_resolver.py),不另做加密。credentials_set 這類帶祕密的 kind,payload 裡的祕密欄位在寫進 agent_requests 前加密(整包加密成一個欄位或逐欄位都可,回寫說明選哪個、為什麼)。加密放 infra 層(repo 或 credential client),app service 不碰金鑰。command_sources_impl.requests_for 組 Command 時才解,Agent 收到的形狀跟現在一樣(Agent 不用改)。解出來的值不進 log(長輪詢回應本來就經 mark_password 遮)。waiting(done/failed/expired)時把 payload 設成 {}(或只留非祕密欄位)——transition、expire_due 兩處。scripts/sql/,照 sql-migration skill:日期註解、-- Date:、收尾 INSERT public.schema_migrations),把已結束列的 payload 清空。只套 DEV。寫完回報「出貨基線待重產」。APP_ENCRYPTION_KEY 時的行為:跟其他整合憑證一致(現行是警告後明文),不要另立一套;回寫寫明。agent_requests.payload 找不到原始密碼字串(任何狀態下都找不到,含 waiting 時)。突變測試:把加密那行拿掉,測試要紅。psql 查 SELECT uid, status, payload FROM compliance.agent_requests ORDER BY id DESC LIMIT 5;:waiting 那一瞬間 payload 是密文、done 之後是空;整張表 grep 不到剛設的密碼。