Skip to content

縱深防禦

Triggerfish 將安全性實作為 13 個獨立、重疊的層。沒有任何單一層足以獨立運作。它們共同形成的防禦能優雅降級——即使某一層被攻破,其餘層仍會繼續保護系統。

安全性 縱深防禦意味著任何單一層的漏洞都不會危及系統。繞過通道驗證的攻擊者仍然面對工作階段 taint 追蹤、策略 hook 和稽核日誌。被提示注入攻擊的 LLM 仍然無法影響其下方的確定性策略層。 :::

13 個防禦層

第 1 層:通道驗證

防禦目標: 冒充、未授權存取、身份混淆。

身份由工作階段建立時的程式碼決定,而非 LLM 解讀訊息內容。在 LLM 看到任何訊息之前,通道適配器會用不可變標籤標記它:

{ source: "owner" }    -- 已驗證的通道身份與註冊擁有者相符
{ source: "external" } -- 其他任何人;僅輸入,不視為指令

驗證方法因通道而異:

通道方法驗證
Telegram / WhatsApp配對碼一次性驗證碼,5 分鐘過期,從使用者帳戶發送
Slack / Discord / TeamsOAuth平台 OAuth 授權流程,回傳已驗證的使用者 ID
CLI本機程序在使用者機器上執行,由作業系統驗證
WebChat無(公開)所有訪客都是 EXTERNAL,永遠不是 owner
電子郵件域名配對寄件者域名與設定的內部域名比對

LLM 永遠不會決定誰是擁有者。來自未驗證發送者的「我是擁有者」訊息會被標記為 { source: "external" },且無法觸發擁有者級別的指令。此決策在 LLM 處理訊息之前就由程式碼做出。 :::

第 2 層:權限感知資料存取

防禦目標: 過度授權的資料存取、透過系統憑證的權限提升。

Triggerfish 使用使用者的委派 OAuth 權杖——而非系統服務帳戶——來查詢外部系統。來源系統執行其自身的權限模型:

傳統 vs Triggerfish:傳統模型給 LLM 直接控制權,Triggerfish 將所有操作路由通過確定性策略層

Plugin SDK 在 API 層級強制執行:

SDK 方法行為
sdk.get_user_credential(integration)回傳使用者的委派 OAuth 權杖
sdk.query_as_user(integration, query)以使用者的權限執行
sdk.get_system_credential(name)被封鎖 — 引發 PermissionError

第 3 層:工作階段 Taint 追蹤

防禦目標: 透過上下文汙染的資料洩漏、分類資料到達較低分類通道。

每個工作階段獨立追蹤 taint 等級,反映工作階段期間存取的最高分類資料。Taint 遵循三個不變量:

  1. 按對話計算 — 每個工作階段有自己的 taint
  2. 僅能提升 — taint 增加,永不降低
  3. 完全重設清除一切 — taint 和記錄一起被清除

當策略引擎評估輸出時,它會比較工作階段的 taint 與目標通道的有效分類。如果 taint 超過目標,輸出被封鎖。

第 4 層:資料血統

防禦目標: 不可追蹤的資料流、無法稽核資料去向、合規缺口。

每個資料元素從來源到目的地都攜帶來源中繼資料:

  • 來源:哪個整合、記錄和使用者存取產生了此資料
  • 分類:分配了什麼等級以及原因
  • 轉換:LLM 如何修改、摘要或合併資料
  • 目的地:哪個工作階段和通道接收了輸出

血統支援正向追蹤(「這條 Salesforce 記錄去了哪裡?」)、反向追蹤(「哪些來源貢獻了此輸出?」)和完整的合規匯出。

第 5 層:策略執行 Hook

防禦目標: 提示注入攻擊、LLM 驅動的安全繞過、不受控的工具執行。

八個確定性 hook 在資料流的關鍵點攔截每個操作:

Hook攔截內容
PRE_CONTEXT_INJECTION進入上下文視窗的外部輸入
PRE_TOOL_CALLLLM 請求工具執行
POST_TOOL_RESPONSE從工具執行返回的資料
PRE_OUTPUT即將離開系統的回應
SECRET_ACCESS憑證存取請求
SESSION_RESETTaint 重設請求
AGENT_INVOCATION代理對代理的呼叫
MCP_TOOL_CALLMCP 伺服器工具呼叫

Hook 是純程式碼:確定性、同步、有記錄且不可偽造。LLM 無法繞過它們,因為不存在從 LLM 輸出到 hook 配置的路徑。Hook 層不會解析 LLM 輸出中的指令。

第 6 層:MCP Gateway

防禦目標: 不受控的外部工具存取、未分類資料透過 MCP 伺服器進入、結構描述違規。

所有 MCP 伺服器預設為 UNTRUSTED,在管理員或使用者分類之前無法被呼叫。Gateway 強制執行:

  • 伺服器驗證和分類狀態
  • 工具層級權限(即使伺服器被允許,個別工具也可被封鎖)
  • 請求/回應結構描述驗證
  • 所有 MCP 回應的 taint 追蹤
  • 參數中的注入模式掃描
MCP 伺服器狀態:UNTRUSTED(預設)、CLASSIFIED(已審查並允許)、BLOCKED(明確禁止)

第 7 層:Plugin 沙盒

防禦目標: 惡意或有缺陷的 plugin 程式碼、資料竊取、未授權的系統存取。

Plugin 在雙重沙盒中執行:

Plugin 沙盒:Deno 沙盒包裹 WASM 沙盒,plugin 程式碼在最內層執行

Plugin 不能:

  • 存取未宣告的網路端點
  • 發出沒有分類標籤的資料
  • 讀取資料而不觸發 taint 傳播
  • 在 Triggerfish 外部持久化資料
  • 使用系統憑證(僅使用者的委派憑證)
  • 透過旁通道竊取資料(資源限制,無原始 socket)

Plugin 沙盒與代理執行環境不同。Plugin 是系統需要保護_的_不受信任程式碼。執行環境是代理被_允許_建構的工作區——有策略管控的存取,而非沙盒隔離。 :::

第 8 層:密鑰隔離

防禦目標: 憑證竊取、設定檔中的密鑰、純文字憑證儲存。

憑證儲存在作業系統金鑰鏈(個人版)或 Vault 整合(企業版)中。它們永遠不會出現在:

  • 設定檔中
  • StorageProvider 值中
  • 日誌條目中
  • LLM 上下文中(憑證在 HTTP 層注入,在 LLM 之下)

SECRET_ACCESS hook 記錄每次憑證存取,包括請求的 plugin、憑證範圍和決策。

第 9 層:檔案系統工具沙盒

防禦目標: 路徑穿越攻擊、未授權的檔案存取、透過直接檔案系統操作的分類繞過。

所有檔案系統工具操作(讀取、寫入、編輯、列表、搜尋)都在沙盒化的 Deno Worker 中執行,其作業系統級別的權限範圍限定在工作階段 taint 對應的工作區子目錄。沙盒強制執行三個邊界:

  • 路徑監禁 — 每個路徑被解析為絕對路徑,並以分隔符感知的配對方式對照監禁根目錄檢查。逸出工作區的穿越嘗試(../)在任何 I/O 發生之前就被拒絕
  • 路徑分類 — 每個檔案系統路徑透過固定解析鏈進行分類:硬編碼受保護路徑(RESTRICTED)、工作區分類目錄、設定的路徑映射,然後是預設分類。代理無法存取超過其工作階段 taint 的路徑
  • Taint 範圍權限 — 沙盒 Worker 的 Deno 權限被設定為與工作階段當前 taint 等級匹配的工作區子目錄。當 taint 提升時,Worker 以擴展的權限重新產生。權限在工作階段內只能擴大,永不縮小
  • 寫入保護 — 關鍵檔案(TRIGGER.mdtriggerfish.yamlSPINE.md)在工具層被寫入保護,與沙盒權限無關。這些檔案只能透過專門的管理工具修改,這些工具強制執行自己的分類規則

第 10 層:代理身份

防禦目標: 透過代理鏈的權限提升、透過委派的資料洗白。

當代理呼叫其他代理時,加密委派鏈防止權限提升:

  • 每個代理有一個證書,指定其能力和分類上限
  • 被呼叫者繼承 max(own taint, caller taint) — taint 只能通過鏈增加
  • taint 超過被呼叫者上限的呼叫者被封鎖
  • 循環呼叫被偵測並拒絕
  • 委派深度受限並被強制執行
資料洗白防禦:攻擊路徑在上限檢查處被封鎖,taint 繼承防止輸出到較低分類通道

第 11 層:稽核日誌

防禦目標: 不可偵測的入侵、合規失敗、無法調查事件。

每個安全相關的決策都以完整上下文記錄:

json
{
  "timestamp": "2025-01-29T10:23:45Z",
  "user_id": "user_123",
  "session_id": "sess_456",
  "action": "slack.postMessage",
  "target_channel": "external_webhook",
  "session_taint": "CONFIDENTIAL",
  "target_classification": "PUBLIC",
  "decision": "DENIED",
  "reason": "classification_violation",
  "hook": "PRE_OUTPUT",
  "policy_rules_evaluated": ["rule_001", "rule_002"],
  "lineage_ids": ["lin_789", "lin_790"]
}

記錄的內容:

  • 所有操作請求(允許和拒絕)
  • 分類決策
  • 工作階段 taint 變更
  • 通道驗證事件
  • 策略規則評估
  • 血統記錄建立和更新
  • MCP Gateway 決策
  • 代理對代理的呼叫

稽核日誌無法被停用。這是策略階層中的固定規則。即使組織管理員也無法關閉自己操作的日誌。企業部署可選擇啟用完整內容記錄(包括被封鎖的訊息內容)以滿足鑑識需求。 :::

第 12 層:SSRF 防護

防禦目標: 伺服器端請求偽造、內部網路偵察、雲端中繼資料竊取。

所有出站 HTTP 請求(來自 web_fetchbrowser.navigate 和 plugin 網路存取)先解析 DNS,然後對照硬編碼的私有和保留範圍拒絕清單檢查解析後的 IP。這防止攻擊者透過精心製作的 URL 誘騙代理存取內部服務。

  • 私有範圍(10.0.0.0/8172.16.0.0/12192.168.0.0/16)始終被封鎖
  • 本地鏈路(169.254.0.0/16)和雲端中繼資料端點被封鎖
  • 環回位址(127.0.0.0/8)被封鎖
  • 拒絕清單是硬編碼的,不可配置——沒有管理員覆蓋
  • DNS 解析在請求之前進行,防止 DNS 重繫結攻擊

第 13 層:記憶體分類閘控

防禦目標: 透過記憶體的跨工作階段資料洩漏、透過記憶體寫入的分類降級、對分類記憶體的未授權存取。

跨工作階段記憶體系統在寫入和讀取時都強制執行分類:

  • 寫入:記憶體條目被強制設為當前工作階段的 taint 等級。LLM 無法為儲存的記憶體選擇較低的分類。
  • 讀取:記憶體查詢以 canFlowTo 過濾——工作階段只能讀取等於或低於其當前 taint 等級的記憶體。

這防止代理將 CONFIDENTIAL 資料以 PUBLIC 身份儲存在記憶體中,然後在較低 taint 的工作階段中取回以繞過禁止降級寫入規則。

信任層級

信任模型定義了誰對什麼有權限。較高層級無法繞過較低層級的安全規則,但可以配置這些規則中的可調參數。

信任層級:Triggerfish 供應商(零存取)、組織管理員(設定策略)、員工(在邊界內使用代理)

個人版: 使用者就是組織管理員。完全自主。Triggerfish 無法查看。供應商預設對使用者資料零存取,且只能透過使用者的明確、有時限、有記錄的授予來獲得存取權。 :::

各層如何協同運作

考慮一個提示注入攻擊,惡意訊息嘗試竊取資料:

步驟操作
1通道驗證訊息標記為 { source: "external" } — 非擁有者
2PRE_CONTEXT_INJECTION輸入掃描注入模式,進行分類
3工作階段 taint工作階段 taint 不變(未存取分類資料)
4LLM 處理訊息LLM 可能被操控請求工具呼叫
5PRE_TOOL_CALL對照外部來源規則進行工具權限檢查
6POST_TOOL_RESPONSE任何返回的資料被分類,taint 更新
7PRE_OUTPUT輸出分類與目標的比對檢查
8稽核日誌整個序列被記錄以供審查

即使 LLM 在步驟 4 被完全攻陷並請求資料竊取工具呼叫,其餘層(權限檢查、taint 追蹤、輸出分類、稽核日誌)仍會繼續執行策略。沒有單點失敗會危及系統。