brandy-savage/hot-potato
GitHub: brandy-savage/hot-potato
为 AI Agent 提供基于污点追踪和能力防火墙的 Prompt 注入防护框架,防止不可信内容引发越权操作。
Stars: 4 | Forks: 0
# hot-potato
能力安全的 agent 编排 —— 防止不受信任的内容在 AI agent 中引发权限提升。
## 问题所在
任何浏览网页、读取文件或使用 RAG 的 AI agent,只要碰到一个恶意文档,就可能泄露凭据、写入文件系统,或者执行操作者根本未曾预期的链式工具调用。内容传达给模型;模型调用工具;工具引发现实世界的后果。这种信任边界在设计上就是模糊的。
Hot-potato 明确地执行了该边界:
- 每个不受信任的产物都会获得一个**污点标签**(来源、信任级别、谱系)
- **检测器**在任何模型看到内容之前扫描注入信号
- **能力防火墙**拦截所有工具调用,并根据 YAML 策略对其进行评估
- **信任图**追踪哪个外部 URL 导致了哪个工具执行
- **重放引擎**在不使用 Docker 的情况下,跨所有攻击类别对覆盖率进行基准测试
## 架构
```
Untrusted content (URL / file / RAG / tool output)
│
▼
TaintedArtifact ─── TrustLevel: UNTRUSTED / SEMI_TRUSTED / TRUSTED / SYSTEM
│ lineage, content_hash, taint_tags
▼
DetectorPipeline
├── StaticDetector (regex, homoglyphs, encodings — fast, no Docker)
└── BehavioralDetector (instruction-flow, authority-shift, priv-esc)
│
▼ taint_tags annotated
CapabilityFirewall ─── PolicyEngine (YAML rules, first-match, dry-run mode)
│
│ Outcomes: allow / deny / redact / require_human_review /
│ sandbox_only / shadow_execute
▼
Tool execution (or block)
│
▼
TrustGraph ─── DAG: which source caused which tool call
TelemetrySession ─── structured audit log, exportable JSON/JSONL
```
## 快速开始
```
# 筛选(向后兼容)
from hot_potato import safe_fetch
result = safe_fetch("https://example.com")
if result.clean:
pass_to_real_ai(result.safe_content)
else:
print(f"Injection detected: {result.artifact['taint']['taint_tags']}")
```
## Agent 集成
```
from hot_potato.core.taint import TaintedArtifact, TrustLevel
from hot_potato.core.capabilities import CapabilityFirewall, CapabilityRequest
from hot_potato.detectors import DetectorPipeline
# 1. 当 artifact 进入 pipeline 时对其进行 taint
artifact = TaintedArtifact(content=content, source=url, trust_level=TrustLevel.UNTRUSTED)
# 2. 运行 detectors — 标注 taint_tags
artifact = DetectorPipeline.default().run(artifact)
# 3. 在 ANY tool call 之前,检查 firewall
firewall = CapabilityFirewall()
request = CapabilityRequest(
tool_name="send_http",
args={"url": "https://api.example.com", "data": payload},
tainted_inputs=[artifact],
)
decision = firewall.evaluate(request)
if decision.is_blocked:
raise RuntimeError(f"Blocked: {decision.reason}")
```
## 使用 ArtifactSwarm 进行批量筛查
```
from hot_potato import ArtifactSwarm
from hot_potato.core.taint import TaintedArtifact, TrustLevel
swarm = ArtifactSwarm(workers=8)
artifacts = [
TaintedArtifact(content=c, source=url, trust_level=TrustLevel.UNTRUSTED)
for url, c in urls_and_contents
]
jobs = swarm.submit_many(artifacts)
for result in swarm.as_completed():
if result.blocked:
print(f"Blocked: {result.job_id} — {result.severity}")
```
## 策略
策略位于 `policies/default.yaml`。规则是声明式的并自上而下进行评估;首条匹配生效。
```
rules:
- id: block_exfil_untrusted
match:
tools: ["send_http", "send_email", "send_crypto"]
trust_levels: [UNTRUSTED]
outcome: deny
reason: "Outbound network from UNTRUSTED content is exfiltration"
- id: sandbox_writes
match:
tools: ["write_file", "write_memory"]
trust_levels: [UNTRUSTED]
outcome: sandbox_only
- id: human_review_crypto
match:
tools: ["get_private_key", "send_crypto", "sign_transaction"]
trust_levels: ["*"]
outcome: require_human_review
```
六种结果:`allow` · `deny` · `redact` · `require_human_review` · `sandbox_only` · `shadow_execute`
## 信任级别
| 级别 | 用例 |
|---|---|
| `UNTRUSTED` | 外部 URL、用户提供的文件、RAG 结果、工具输出 |
| `SEMI_TRUSTED` | 内部 API、缓存内容、来自 TRUSTED 进程的输出 |
| `TRUSTED` | 操作者自己的代码库、已验证的配置 |
| `SYSTEM` | Runtime 本身 —— 不可能被注入 |
信任度永远不会通过派生而增加。即使经过受信任系统的处理,从 UNTRUSTED 输入派生的内容
依然是 UNTRUSTED。
## 框架集成
```
# OpenAI tool-call 循环
from integrations.openai_compat import GuardedToolExecutor
executor = GuardedToolExecutor(tools=my_tools, model="gpt-4o")
for tool_call in response.choices[0].message.tool_calls:
result = executor.execute(tool_call, tainted_inputs=[artifact])
# MCP server
from integrations.mcp_guard import MCPGuard
guard = MCPGuard()
decision = guard.evaluate_mcp_call("read_file", {"path": "/etc"}, tainted_sources=[artifact])
# LangChain
from integrations.langchain_guard import GuardedTool, set_taint_context
set_taint_context([artifact])
guarded_tool = GuardedTool.wrap(my_langchain_tool)
```
## 行为沙箱后端
Hot-potato 内置了两个行为沙箱后端。静态层 + 防火墙层
在没有这两个后端的情况下也能工作。
### Docker 后端(默认)
```
# 一次性设置 — 将 model 拉取到 named volume 中
hot-potato-setup
# 使用(在使用 safe_fetch/scan_file 和 sandbox 调用时自动执行)
HP_BACKEND=docker hot-potato file:///path/to/file.txt
```
需要 Docker daemon。使用 `--network none`,2 GB 内存限制,overlay FS。
启动时间:约 3–8 秒。
### 原生后端 (bwrap — 无需 daemon)
```
# 一次性设置 — 安装 bubblewrap + AppArmor profile
apt install bubblewrap
sudo cp setup/apparmor_bwrap.profile /etc/apparmor.d/bwrap
sudo apparmor_parser -r /etc/apparmor.d/bwrap
# 使用
HP_BACKEND=native hot-potato file:///path/to/file.txt
```
需要:`bwrap` (bubblewrap)、Linux kernel 4.18+、在 localhost 上运行的 Ollama。
启动时间:约 200 ms。
隔离层:
| 层级 | Docker | 原生 |
|---|---|---|
| 一次性 FS | overlay2 | tmpfs root |
| 进程隔离 | cgroup + namespace | PID + user namespace |
| 网络隔离 | `--network none` | 应用层(伪处理器) |
| Syscall 过滤器 | Docker 默认 seccomp | 自定义 BPF(拦截 41 个 + 架构检查) |
| Capability 剥离 | Docker 默认配置 | `CAP_DROP ALL` + NO_NEW_PRIVS |
| 需要 Root | 是(daemon) | 否 |
有关涵盖 symlink 遍历、ptrace、SUID、fork 炸弹、netlink 和 kernel 漏洞的完整逃逸向量分析,请参阅 `docs/native_sandbox.md`。
```
from hot_potato import native_sandbox_available
print(native_sandbox_available()) # True if bwrap is installed and userns enabled
```
## 基准测试
```
# 快速(无 Docker)— static + behavioral + firewall 层
python3 benchmarks/run_benchmark.py
# 完整 sandbox(Docker)
python3 benchmarks/run_benchmark.py --sandbox --out results/bench.json
# 完整 sandbox(原生)
HP_BACKEND=native python3 benchmarks/run_benchmark.py --sandbox --out results/bench_native.json
```
针对 73 个对抗类别(SCANNER_VERSION 1.10.0)的结果:
| 层级 | 检出率 | 备注 |
|---|---|---|
| 静态 (regex) | 98.6% (72/73) | cat6 故意设置为无信号 —— 需要沙箱 |
| 行为 | — (Phase 2) | |
| 能力防火墙 | 策略完备 | 所有已定义规则均正确触发;覆盖率取决于您的策略 |
## 与其他工具的正面对比
相同的 73 类语料库,相同的已知正常文件([完整结果](benchmarks/results/head_to_head.md)):
| 工具 | 检出率 | 严重漏报 | 误报 (已知正常文档) | 平均延迟 |
|---|---|---|---|---|
| **hot-potato-static** | **98.6% (72/73)** | **0** | 5/5 ¹ | 35 ms |
| llm-guard-v2 | 13.7% (10/73) | 62 | 0/5 | 73 ms |
| rebuff-heuristic | 0.0% (0/73) | 72 | 0/5 | 87,745 ms |
¹ hot-potato 在这 5 个已知正常文件上的误报,属于自然包含注入词汇的安全文档(IR playbook、API 参考等)。这是预期且正确的行为 —— 对于第一方内容,请指定 `TrustLevel.TRUSTED`。参见[已知局限性](#known-limitations)。
合法 skill 文件的误报率:**~9%**(扫描了来自 skills.sh 的 630 个 skill —— 误报主要来自带有 `