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 之外持久化数据
  • 使用系统凭证(仅用户的委托凭证)
  • 通过侧信道外泄数据(资源限制,无原始套接字)

Plugin 沙箱不同于智能体执行环境。Plugin 是系统_保护自身免受_的不受信代码。执行环境是智能体被允许_构建_的工作区——具有策略管控的访问,而非沙箱隔离。 :::

第 8 层:密钥隔离

防范: 凭证被盗、配置文件中的密钥、明文凭证存储。

凭证存储在操作系统钥匙串(个人版)或保管库集成(企业版)中。它们永远不会出现在:

  • 配置文件
  • 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 跟踪、输出分类、审计日志)仍继续执行策略。没有单点故障能危及系统。