事件經過
安全研究公司 Noma Labs 為了測試,開啟了 Salesforce 的潛在客戶收集表單功能。這個功能讓外部的人在公司網站的表單上填入自己的資料,而他們填的內容會直接進入該公司的客戶資料。接著 Salesforce 的 AI 助理 Agentforce 就能讀取這些資料,回答員工關於它們的問題。
研究人員逐一檢視表單的欄位,記下每個欄位能容納多少文字。姓名欄位是 40 與 80 個字元。邀請訪客描述自身需求的那個欄位可容納 42,000 個字元,足以放進一長串書面要求。他們也向助理問了一個與銷售資料毫無關係的一般知識問題,助理回答了。
他們在那個長欄位裡寫下一份編號清單:公司有多少筆潛在客戶、這些潛在客戶帶著哪些電子郵件地址,最後再要求加上一張小小的預覽圖片,圖片從某個網址載入,而那些電子郵件地址就附掛在該網址後面。接著一位員工做了一件很平常的事:請助理查看這筆新的潛在客戶,並回覆它提出的問題。助理把員工的要求,和擺在旁邊那段欄位裡的文字,一起照做了。
那個圖片網址用的名稱,就在 Salesforce 允許其頁面載入圖片的來源清單上。該名稱的註冊已經到期,正在出售。研究人員花 5 美元買下一個網域,指向自己的伺服器,並記錄進來的請求。潛在客戶的電子郵件地址抵達了那裡。Noma Labs 將這項發現評為 9.4,並稱之為關鍵嚴重性。
Noma Labs 在 7 月向 Salesforce 報告,Salesforce 在幾天內確認。Salesforce 重新取回並保護了那個已過期的網址,並在 9 月為 Agentforce 與 Einstein AI 導入受信任網址的強制執行;該公司表示已釋出修補,阻止 Agentforce 助理的輸出被送往未受信任的網址。這項研究在同年 9 月下旬公開。研究之外是否有人用這條路徑對某家公司下手,無從得知;是否有任何真實的客戶資訊離開任何人的資料,也無從得知。
主要來源——S1:https://noma.security/blog/forcedleak-agent-risks-exposed-in-salesforce-agentforce
損失成因
- 一個對任何人開放的表單欄位,把最多 42,000 字元的陌生人文字,沿著員工要求所走的同一條路帶進助理,而助理把它當成一件要辦的工作照做 訪客打進去的文字被存成客戶資料的一部分,當助理讀取那筆資料時,訪客寫的句子就和員工自己的要求擺在同一個地方。它們抵達的方式沒有任何一點能標示出哪一個是要回答的問題、哪一個只是要回報的文字,所以一個夠長的欄位就裝得下一整套命令。技術名稱:間接提示注入(indirect prompt injection)
- 決定哪些句子算是命令的,只有正在讀那些句子的助理本身,於是能誤導它的文字,同樣通過了它自己的檢查 當「什麼算是指令」的裁判就住在正被操控的那個模型裡,就沒有一道獨立的界線可以讓文字過不了關。寫進助理自身簡報(system prompt)裡的規則,和它們原本要過濾的文字,走的是同一條管道。技術名稱:自我裁決的指令(self-adjudicated instructions)
- 一份長期存在的清單列著系統可以載入圖片的網址,上面仍留著一個註冊已到期、正在出售的名稱,於是一台外部伺服器能繼承那份受信任的地位 這份清單核對的是名字,不是這個名字現在歸誰所有,而一個到期註冊的所有權可以轉到任何買下它的人手上。一旦清單上的名稱指向別人的伺服器,一個被允許的圖片請求,就成了一條可用的出口,把寫進網址裡的任何東西帶出去。技術名稱:失效的允許清單項目(過期網域仍被信任)(lapsed allowlist entry)
判讀
當助理會讀取公開收件表單所收到的一切內容時,決定能塞進多少外部指示的,是那張表單上最寬鬆的自由填寫欄位,而不是任何帳戶的大小或權限。填姓名的短欄位塞不進什麼;一個邀請陌生人描述需求的長欄位,卻能裝下一整套指令,而助理分不出它和自己的指令有什麼不同。
自我查核
只有你能回答的
- 當你開啟一張任何人都能填的公開表單時,你是刻意決定讓你的 AI 助理之後會讀取這些答案,還是這件事是你隨著這項功能一起繼承下來的預設值?
- 你是不是把表單上那個「告訴我們你的需求」長欄位,當成寫給人看的句子?在知道助理也會讀它們之後,你還會把它留得這麼長嗎?
- 當一段陌生人寫的文字就躺在助理正在讀的那筆資料裡時,你願意讓多少客戶名單留在助理的觸及範圍之內?
你的 AI 可以幫你查的
僅提出報告;不要變更任何程式碼或設定。每個問題的每一項主張,都請附上檔案或主控台的出處;若依現有資料無法判定,請直接說明。
- 列出我們所有對外的收件與潛在客戶收集表單上的每一個欄位、每個欄位的最大字元長度,以及當員工查詢某筆資料時,該欄位儲存的內容是否可被 AI 助理或檢索流程讀取;請針對表單定義與助理所設定的資料來源,附上檔案或主控台出處。
- 搜尋已儲存的潛在客戶與表單送出內容,找出含有命令式語句、HTML 標記、圖片標籤,或帶有編碼參數的網址的項目,並依欄位回報資料識別碼與筆數;請針對所使用的查詢與回傳的資料,附上檔案或主控台出處。
- 回報是否有模型之外的任何東西在限制助理可以對哪些檢索到的文字採取行動:列出位於資料內容與 agent 行動之間的每一個政策引擎、輸出過濾、工具權限界線或核准步驟,並明確說明這類規則是否只寫在 system prompt 裡;請附上檔案或主控台出處。
- 清點應用程式與所有 AI agent 設定中,受信任網址清單、內容安全政策(CSP)與對外連線目的地允許清單裡的每一個項目,並就每個網域回報目前的註冊人與註冊到期日,標示出任何未註冊、已到期或即將到期者;請附上檔案或主控台出處。
預防方式
**把公開表單上的那個長欄位,變成一個決定,而不是預設值。**看看你的網站表單,逐一問每個欄位到底是做什麼用的。把自由填寫的欄位縮短到一則銷售回覆真正需要的長度,或改成一份簡短的選項清單;只有在你接受「陌生人在那裡寫的任何東西都會被唸給你的助理聽」的地方,才保留長欄位。凡是保留的地方,就用書面向你的供應商提問:助理讀到那個欄位時,是把裡面的內容當成要回報的文字,還是當成要執行的工作?
**假設你的助理讀到的任何東西都能操控它,並把這個假設算進成本裡。**你無法改變 Salesforce 的助理如何權衡它讀到的文字,所以就從「它會被任何落進資料裡的東西操控」這個假設出發。以書面向 Salesforce 詢問:在助理之外,有什麼東西在決定它可以遵循哪些指令?並把答案連同日期存檔。在答案還不明確之前,讓助理的觸及範圍保持狹窄:只給它員工當下正在處理的那一筆資料,而不是對整份客戶名單的常設存取權,並把最敏感的名單擺在它看不到的地方。
**問清楚受信任清單上每一個名稱現在歸誰所有,並且定期再問一次。**要求 Salesforce 以書面確認:受信任網址的強制執行在你的帳戶上是開啟的,而且那些受信任的名稱會被重新檢查是否有註冊到期的情況,不是只檢查一次。對任何其他為你保管核准網址清單的供應商,以及管理你自己網域的人,提出同樣的問題:哪些註冊即將到期續約,誰在盯著。從現在起,把清單上一個熟悉的名稱只當成一個名稱,而不是「今天由誰持有」的證明。
你公開表單上最長的那個欄位,就是陌生人能交給你助理的最長一份命令。