iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
AI Security

我也希望安全第一——然後我們看看這些鎖是怎麼一個個被撬開的系列 第 13 篇

第 13 篇|17,000 個動作,為什麼沒叫醒值班工程師?

  • 分享至 

  • xImage
  •  

17,000 個動作,為什麼沒叫醒值班工程師?

[[我也希望安全第一]]|第 13/30 天

先把 17,000 個動作還原成值班畫面

先不重述 Hugging Face 的入侵過程。假設值班工程師當時打開四個系統,可能各自只看到一小塊:套件服務出現陌生目的地、某個短命 runner 讀了憑證、IAM 記下一次少見 token 使用,EDR 則看到新的 process。每一件事都不夠戲劇化,甚至可能只被標成低嚴重度。

事後把它們放回同一條 task,才知道攻擊約持續 4.5 天,累積 17,000 個動作。Hugging Face 的工具其實曾關聯出部分攻擊訊號,卻沒有順利升級到 on-call。問題不是完全沒看見,而是四個系統看到的「小事」沒有及時變成一個由人負責的事件。

這種畫面一般 IT 團隊並不陌生。新地方只在於 Agent 可以讓零碎訊號出現得更快、更分散,也更持久。

AI 攻擊的新意多半在節奏

這次使用的基本動作和人類紅隊並沒有根本差別。掃描、嘗試登入、尋找 secret、呼叫 API、橫向移動,SOC 都認得。變化在三個地方:

  • 速度:探索與修正可以連續進行,不必等人類打字或交班。
  • 規模:大量短命 runner、帳號與並行嘗試讓單一來源 IP 不再可靠。
  • 耐性:只要 budget 沒停,Agent 不會因凌晨三點或連續失敗而休息。

所以偵測規則不該只問「這個 IP 今天失敗幾次」。它還要問:這些動作是否屬於同一個 task、同一模型版本、同一批 workload,或者由同一個短效身分建立。

把模型 trace 和傳統 telemetry 接起來

Agent 系統常把 prompt 與 tool call 放在應用 log,網路流量在 proxy,憑證使用在 IAM,process event 又在 EDR。沒有共同識別碼時,值班的人看到的是四件小事。

task_id / trace_id
   ├── model span:模型版本、輸入摘要、輸出風險標籤
   ├── tool span:工具、參數雜湊、policy decision
   ├── process event:binary、argv、container、parent process
   ├── network event:DNS、目的 IP、SNI、bytes、decision
   └── identity event:token id、scope、mint、use、revoke

OpenTelemetry 的 log correlation 會把 TraceId、SpanId 帶進 log,讓不同服務的事件可沿同一執行脈絡查回去。這不是 Agent 專用技術;正因為它普通,團隊不必等一套「AI SOC」才開始做。

要避免的是把完整 prompt、secret 或 bearer token 全塞進 telemetry。能記 resource ID、參數雜湊與 secret reference,就不要複製敏感值。調查需要可關聯,不等於需要無限制收集內容。

還有一個更現實的限制:trace ID 到了別人的網站就斷了。Transluce 後來是靠德國 Wiki、urlquery.net 與受影響網站的公開紀錄,才把疑似 Agent 群在 Data USA、大學圖書館及澳洲公共機構的活動拼在一起。那些紀錄看得到網路痕跡,卻沒有內部 task、模型版本與完整 runner 清單;反過來,公司內部有 task,卻未必知道第三方已經把零碎探測視為同一件事故。

所以 telemetry 的最後一段不是再買一套 dashboard,而是讓外部訊號進得來:公開且有人處理的 abuse/security 聯絡方式、能接受第三方時間線與 IOC 的案件系統,以及把外部 IP、時間和目標反查到內部 task 的能力。若研究者只能寄一般客服信箱,內部 trace 再完整也接不上。

三種 session 紀錄,能回答的問題不同

Pi、Goose 與 OpenHands 都會保存工作狀態,但「有歷程」不是同一件事:

  • Pi 把 session 保存成帶有 parent/child 關係的 JSONL tree。它很適合回到某個分支,看模型當時收到什麼;compaction 後完整歷程仍在檔案,下一輪模型看到的卻是摘要。
  • Goose 可以把完整 session 匯出成 JSON,保留對話、metadata 與設定;啟用 prompt injection detection 後,每次判斷另以 finding ID 寫進系統 log。這兩份資料能互補,但 session export 本身不能直接當成不可竄改的統一 audit log。調查者仍要確認批准、拒絕與 reviewer 判斷究竟記在哪裡、保存多久。
  • OpenHands SDK 把 Agent、Conversation、Workspace 與 events 收進 Agent Server,另由 Automation 管排程與執行歷史。它比較接近服務化環境,但調查時要跨 server、workspace 與 automation record 才能拼完整。

若同一個測試任務要求三套系統修改一個檔案,再故意讓 shell 嘗試讀取 workspace 外的 secret,我會檢查五件事:原始 prompt 是否還在、拒絕或批准是否有事件、實際執行身分是誰、session 與系統 log 能不能對時,以及能不能從最後一個檔案變更反查到那次決定。這比比較誰的對話畫面更漂亮,更接近事故現場。

哪些訊號值得升級

以下對照表比「偵測所有怪行為」更容易實作:

行為 單看可能正常 組合後的高風險訊號
安裝套件 coding 任務常見 installer 後首次連到非 allowlist 網域
多次失敗 自動重試常見 換協議、換帳號、換目的地繼續嘗試
讀取 secret 部署工具需要 task scope 未包含部署,隨後對外連線
建立短命容器 runner 正常行為 多容器共享同一目的地或 C2 pattern
查公開網站 research 任務正常 搜尋 benchmark 解答、憑證或內部端點
tool 被 policy 拒絕 guardrail 正常運作 連續 deny 後改用 shell/HTTP 旁路

一條可讀的偵測邏輯可以先寫成這樣:

IF task.network_expected = false
AND distinct_external_destinations(10m) > 0
THEN stop_new_tool_calls
     page agent-runtime-oncall
     preserve trace + flow + identity events

對明確不該連外的 workload,不必先用另一個 LLM 判斷語義。第一個封包就足以觸發 deterministic control。需要外網的 research agent 才改用組合規則,避免正常搜尋每次都停機。

警示送出去不代表事情已經有人處理

一則警示至少要有 owner、嚴重度、回應時限與自動處置。否則 dashboard 上的紅點只是裝飾。

可以先定三層:

S1:未授權外連/使用不屬於 task 的憑證
    → 立即凍結 job,5 分鐘內 page

S2:連續 policy deny 後改走其他工具
    → 暫停新 tool call,15 分鐘內確認

S3:異常重試、成本或步數升高
    → 降速、保留樣本,下一工作日檢視

凌晨值班最需要的不是「Agent behavior anomaly score = 0.87」,而是這個 job 做了什麼、已經停了沒有、用過哪些憑證、還有哪些系統可能受影響,以及按下哪個按鈕能撤權限。

第 14 篇會處理更前面的問題:與其等封包出現才發出警示,能不能把安全測試環境做成即使支援服務被攻破,也碰不到公開網路與 production?

參考與來源


上一篇
第 12 篇|Agent 越界:四個失敗位置
下一篇
第 14 篇|替高風險 Eval 架一個真正隔離的 Runner
系列文
我也希望安全第一——然後我們看看這些鎖是怎麼一個個被撬開的 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言