内容
<div align="center">
<!-- Animated Typing Header -->
<a href="https://github.com/sattyamjjain/agent-airlock">
<img src="https://readme-typing-svg.demolab.com?font=Fira+Code&weight=700&size=28&duration=3000&pause=1000&color=00D4FF¢er=true&vCenter=true&multiline=true&repeat=true&width=700&height=100&lines=%F0%9F%9B%A1%EF%B8%8F+Agent-Airlock;Your+AI+Agent+Just+Tried+rm+-rf+%2F.+We+Stopped+It." alt="Agent-Airlock Typing Animation" />
</a>
### AI 代理工具调用的类型检查和合约层 - 默认拒绝,进程内,无依赖
**严格验证,伪参数剥离和自我修复重试 - 一个装饰器,适用于任何代理或 MCP 服务器**
<!-- Primary Badges Row -->
[](https://pypi.org/project/agent-airlock/)
[](https://pypistats.org/packages/agent-airlock)
[](https://github.com/sattyamjjain/agent-airlock/actions/workflows/ci.yml)
[](https://codecov.io/gh/sattyamjjain/agent-airlock)
<!-- Secondary Badges Row -->
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
[](https://github.com/sattyamjjain/agent-airlock/stargazers)
[](http://makeapullrequest.com)
<!-- TEST-BADGE-START -->
<!-- Auto-generated by scripts/update_test_badge.py. Do not edit by hand. -->
**测试套件:** 3,292 tests · **覆盖率:** 85.02% · **v0.8.40**
<!-- TEST-BADGE-END -->
<br/>
[**30 秒快速入门**](#-30-秒快速入门) · [**为什么选择 Airlock?**](#-没有人讨论的问题) · [**所有框架**](#-框架兼容性) · [**基准测试**](BENCHMARK.md) · [**跨工具比较**](benchmarks/blockrate/RESULTS.md) · [**最小权限基准测试**](benchmarks/toolprivbench/RESULTS.md) · [**文档**](#-文档)
**⬛ 可复制的阻塞率 - 确定性,进程内,默认拒绝**
| 基准测试(一个命令即可复制) | agent-airlock | 比较 |
|---|---|---|
| **跨工具阻塞率** · 210 工具调用 · `python -m benchmarks.blockrate` | **100% 阻塞 · 0% 误报 · p50 ~2µs/决策** | Meta LlamaFirewall · Invariant Guardrails — _模型循环;范围声称,**未重新运行**_ |
| **最小权限 / 特权工具选择** · ToolPrivBench,100 个场景,OWASP-Agentic 映射(ASI03 / ASI06) | **100% 特权工具阻塞 · 100% 低权限工具允许** | — |
| **防护套件 CVE 语料库** · MCP Top-10 标记 | **100% 检测 · 0% 误报** | — |
[`BENCHMARK.md`](BENCHMARK.md) · [`benchmarks/blockrate/RESULTS.md`](benchmarks/blockrate/RESULTS.md) · [`benchmarks/toolprivbench/RESULTS.md`](benchmarks/toolprivbench/RESULTS.md) ([ToolPrivBench: arXiv:2606.20023](https://arxiv.org/abs/2606.20023))
> _自我整理的语料库:一个**覆盖率 / 回归基准线**,不是自适应攻击者(ASR)得分。现有的解决方案引用其已发布的检测范围,**未在此处重新运行** — 没有编造竞争对手编号。(AgentDojo 集成是路线图,尚未连接。)_
<br/>
</div>
---
<!-- Hero Visual Block -->
<div align="center">
```
┌────────────────────────────────────────────────────────────────┐
│ 🤖 AI 代理: "让我帮助清理磁盘空间..." │
│ ↓ │
│ rm -rf / --no-preserve-root │
│ ↓ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 🛡️ AIRLOCK: 阻止 │ │
│ │ │ │
│ │ 原因:匹配被拒绝的模式 'rm_*' │ │
│ │ 策略:STRICT_POLICY │ │
│ │ 修复:仅使用批准的清理工具 │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
```
</div>
---
## 🧩 它适合在哪里(与原生 MCP 网关相比)
MCP 网关和平台防火墙 - **Docker MCP 网关,Cloudflare,Azure API Management,AWS**,以及 MCP 规范的 **OAuth 资源服务器授权** - 保护**传输和身份**层:谁允许连接,通过哪个通道,使用哪个令牌。这是必要的,并且它们做得很好。
agent-airlock 位于**内部**,在身份验证之后的执行边界:它验证**实际的工具调用有效载荷**模型生成的 - 参数类型(严格的 Pydantic,无强制转换),幻觉/伪参数,默认拒绝工具和功能范围,以及输出净化 - 然后返回模型可以重试的自我修复错误。网关可以确认调用者已身份验证;它不检查 `transfer(amount=-1)` 是否类型有效或代理是否选择了任务的最小权限工具。
**同时使用。** 网关/ OAuth 连接;airlock 作为进程内调用合约层,用于有效载荷。这是一个装饰器,而不是代理 - 零新的网络跳跃,在您的工具运行的位置运行。
---
## 🎯 30 秒快速入门
```bash
pip install agent-airlock
```
```python
from agent_airlock import Airlock
@Airlock()
def transfer_funds(account: str, amount: int) -> dict:
return {"status": "transferred", "amount": amount}
# LLM 发送 amount="500"(字符串)→ 阻止并修复提示
# LLM 发送 force=True(发明的参数)→ 静默剥离
# LLM 发送 amount=500(正确)→ 安全执行
```
**就是这样。** 您的函数现在具有伪参数剥离,严格类型验证和自我修复错误。
---
## 🧠 没有人讨论的问题
<table>
<tr>
<td width="50%">
### 热点
> *"MCP 有 16,000+ 服务器在 GitHub 上!*"
> *"OpenAI 采用了它!*"
> *"Linux 基金会托管它!*"
</td>
<td width="50%">
### 现实
**LLM 每天都会产生幻觉工具调用。**
- Claude 发明不存在的参数
- GPT-4 发送 `"100"` 当你需要 `100`
- 代理链调用 47 次后,其中一个删除生产数据
</td>
</tr>
</table>
**企业解决方案存在:** Prompt Security($50K/年),Pangea(代理您的数据),Cisco(“即将推出”)。
**我们构建了开源替代方案。** 一个装饰器。无供应商锁定。您的数据永远不会离开您的基础设施。
---
## ✨ 您获得的功能
<table>
<tr>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/delete-shield.png" alt="shield"/>
<br/><b>伪参数</b>
<br/><sub>剥离 LLM 发明的参数</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/checked.png" alt="check"/>
<br/><b>严格类型</b>
<br/><sub>无静默强制转换</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/refresh.png" alt="refresh"/>
<br/><b>自我修复</b>
<br/><sub>LLM 友好的错误</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/lock.png" alt="lock"/>
<br/><b>E2B 沙盒</b>
<br/><sub>隔离执行</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/user-shield.png" alt="user"/>
<br/><b>基于角色的访问控制</b>
<br/><sub>基于角色的访问控制</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/privacy.png" alt="privacy"/>
<br/><b>个人身份信息掩码</b>
<br/><sub>自动编辑密钥</sub>
</td>
</tr>
<tr>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/network-card.png" alt="network"/>
<br/><b>网络防护</b>
<br/><sub>阻止数据泄露</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/folder-invoices.png" alt="folder"/>
<br/><b>路径验证</b>
<br/><sub>CVE 抵抗遍历</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/restart.png" alt="circuit"/>
<br/><b>断路器</b>
<br/><sub>容错</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/analytics.png" alt="otel"/>
<br/><b>OpenTelemetry</b>
<br/><sub>企业可观察性</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/money-bag.png" alt="cost"/>
<br/><b>成本跟踪</b>
<br/><sub>预算限制</sub>
</td>
<td align="center" width="16%">
<img width="40" src="https://img.icons8.com/fluency/48/syringe.png" alt="vaccine"/>
<br/><b>疫苗接种</b>
<br/><sub>自动安全框架</sub>
</td>
</tr>
</table>
---
## 📋 目录
<details>
<summary><b>点击展开完整导航</b></summary>
- [30 秒快速入门](#-30-秒快速入门)
- [问题](#-没有人讨论的问题)
- [您获得的功能](#-您获得的功能)
- [核心功能](#-核心功能)
- [E2B 沙盒执行](#-e2b-沙盒执行)
- [安全策略](#-安全策略)
- [成本控制](#-成本控制)
- [个人身份信息掩码](#-个人身份信息掩码)
- [网络隔离](#-网络隔离-v030)
- [框架疫苗接种](#-框架疫苗接种-v030)
- [断路器](#-断路器-v040)
- [OpenTelemetry](#-opentelemetry-可观察性-v040)
- [框架兼容性](#-框架兼容性)
- [FastMCP 集成](#-fastmcp-集成)
- [比较](#-为什么不使用企业供应商)
- [安装](#-安装)
- [OWASP 合规性](#️-owasp-合规性)
- [性能](#-性能)
- [文档](#-文档)
- [贡献](#-贡献)
- [支持](#-支持)
</details>
---
## 🔥 核心功能
### 🔒 E2B 沙盒执行
```python
from agent_airlock import Airlock, STRICT_POLICY
@Airlock(sandbox=True, sandbox_required=True, policy=STRICT_POLICY)
def execute_code(code: str) -> str:
"""在 E2B Firecracker MicroVM 中运行。不在您的机器上。"""
exec(code)
return "executed"
```
| 功能 | 值 |
|---------|-------|
| 启动时间 | ~125ms 冷启动,<200ms 热启动 |
| 隔离 | Firecracker MicroVM |
| 降级 | `sandbox_required=True` 阻止本地执行 |
如果您的网络是空气隔离的?`DockerBackend` 是支持的替代方案
— `cap_drop=["ALL"]`,`no-new-privileges`,`network_mode="none"`,
超时强制执行,可选的 `pytest -m docker` 集成测试。参见
[`docs/sandbox/docker.md`](docs/sandbox/docker.md)。
#### ModalBackend — Modal 主机沙盒 *(v0.8.11+, 问题 #30)*
您已经在 [Modal](https://modal.com/) 上运行代理的其余部分了吗?
`ModalBackend` 允许您将 airlocked 工具执行保持在同一
基板上,而不是混合 E2B 和 Modal 计费 / 可观察性。
```bash
pip install "agent-airlock[modal]"
```
```python
from agent_airlock import Airlock, STRICT_POLICY, AirlockConfig
from agent_airlock.sandbox_backend import ModalBackend
backend = ModalBackend(
app_name="my-airlock-sandbox",
image_ref="python:3.11-slim",
cpu=0.5,
memory_mb=512,
timeout_s=30,
# network_policy=None → block_network=True(默认关闭)
)
@Airlock(sandbox=True, sandbox_required=True, policy=STRICT_POLICY,
config=AirlockConfig(sandbox_backend=backend))
def execute_code(code: str) -> str:
exec(code)
return "executed"
```
**隔离模型 - 在使用 `cap_drop` 之前阅读。** Modal
沙盒在 **gVisor** 下运行(内核系统调用过滤),不在
Docker 样式的能力下降。Modal Python SDK 不
公开 `cap_drop` / `cap_add` / `seccomp` / `no-new-privileges` -
没有等效的旋钮来映射。如果您的威胁模型需要
Linux 能力在容器层下降,请继续使用
`DockerBackend`。 网络姿势 *是* 可配置的:`ModalBackend`
默认为 `block_network=True`(默认拒绝),并且提供的
`NetworkPolicy` 映射到 Modal 的 `block_network` 标志(`allow_egress=False`
→ 阻止,`True` → 允许)。 主机名允许列表 `NetworkPolicy.allowed_hosts`
不 **转发到 Modal(他们的 API 是 CIDR 仅限);后端日志
一个 structlog 警告,操作员期望在 `Airlock` 策略层重新声明主机名约束。
`ModalBackend` 是 **仅需选择** - 它不添加到
`get_default_backend()` 优先级链(E2B → Docker → Local 保持
默认流程)。 现有调用者看到没有行为变化。
---
### 📜 安全策略
| 预设 | 用例 | 关键姿势 |
|---|---|---|
| `PERMISSIVE_POLICY` | 开发 / 沙盒 | 无限制 |
| `STRICT_POLICY` | 生产 | 速率限制,需要代理身份验证,拒绝危险功能 |
| `READ_ONLY_POLICY` | 分析 / RAG | `read_*` / `get_*` / `list_*` / `search_*` 仅限 |
| `BUSINESS_HOURS_POLICY` | 合规窗口 | `delete_*` / `drop_*` / `*_production` 仅限 09:00–17:00 |
| `CAMOUFLAGE_RESISTANT_POLICY` *(v0.8.6)* | 检测器独立防御 vs. 域名伪装注入 | 默认拒绝允许列表,阻止伪参数,输出上限,每次调用重新授权 |
```python
from agent_airlock import (
PERMISSIVE_POLICY,
STRICT_POLICY,
READ_ONLY_POLICY,
BUSINESS_HOURS_POLICY,
CAMOUFLAGE_RESISTANT_POLICY, # v0.8.6
)
# 或构建自己的:
from agent_airlock import SecurityPolicy
MY_POLICY = SecurityPolicy(
allowed_tools=["read_*", "query_*"],
denied_tools=["delete_*", "drop_*", "rm_*"],
rate_limits={"*": "1000/hour", "write_*": "100/hour"},
time_restrictions={"deploy_*": "09:00-17:00"},
)
```
#### CAMOUFLAGE_RESISTANT - 检测器独立注入防御(v0.8.6)
[arXiv:2605.22001](https://arxiv.org/abs/2605.22001) (“Blind Spots in
the Guard”,Pai,2026 年 5 月)显示,生产环境注入检测器
- **Llama Guard 3** 包括 - 下降到 **IDR = 0.000** 在有效载荷上
模仿目标文档的领域词汇和权威结构。
根据论文,检测率从 93.8% 下降到 9.7% 在 Llama 3.1
8B 和从 100% 下降到 55.6% 在 Gemini 2.0 Flash。
`CAMOUFLAGE_RESISTANT_POLICY` 不依赖有效载荷内容签名。
它在四个结构化接缝处阻止攻击者必须骑乘的攻击:
1. **默认拒绝工具允许列表。** 空的 `allowed_tools` 意味着
*nothing* 是可调用的;部署选择每个工具的名称。
伪装指令针对未列出的工具在允许列表基础上被阻止,
而无需调用检测器。
2. **伪参数阻止。** 伪装指令无法将未声明的参数
偷偷带过验证。
3. **硬输出上限 + 清理。** 工具输出重新进入模型上下文
被截断并 PII/密钥掩码,因此伪装指令嵌入在工具输出中
不能以全长流入下游代理。
4. **每次调用重新授权(辩论放大保护)。** 一旦工具的输出
流回模型,任何重新调用需要一个明确的 `context.authorize_once(tool)`
授予来自外壳 - 打破论文中识别的多智能体扇出路径。
```python
from agent_airlock import Airlock, apply_camouflage_resistant
bundle = apply_camouflage_resistant(allowed_tools=["read_file", "search"])
@Airlock(config=bundle.config, policy=bundle.policy)
def read_file(path: str) -> str:
...
```
`apply_camouflage_resistant()` 组合匹配的 `AirlockConfig`
(未知参数阻止,清理开启,输出上限 4000 个字符)与
`SecurityPolicy` 携带您的显式允许列表。预设是
故意不完整的 - 配置级别旋钮和策略级别旋钮跨越两个接缝,
所以工厂返回两者作为一个 `CamouflageResistantBundle`.
> **运行 STDIO 传输的 MCP 服务器?** 还要连接
> [Ox MCP STDIO 清洁剂](#️-owasp-compliance) 通过
> `stdio_guard_ox_defaults()` - 它阻止整个
> CVE-2026-30616 类别(shell 元字符注入,
> 非允许列表二进制文件,Trojan-Source RTL 覆盖,
> 和内联代码标志)之前 `subprocess.Popen`。
---
### 🪪 MCP 服务器认证(v0.8.10)
[arXiv:2605.24248](https://arxiv.org/abs/2605.24248)(“认证工具服务器准入”,Metere,2026年5月)指出MCP本身并未解决的一个问题:协议规范了LLM代理和工具服务器之间的消息交换,但并未涉及信任问题。任何能够在网络上回答的人都可以声称自己是工具服务器。
`mcp_attested_admission_defaults()` 是一个默认拒绝的选项预设,它在主机端关闭了这个漏洞,镜像了论文中的三个附加机制:
1. **离线签名许可声明**。在任何来自MCP服务器的工具被调度之前,主机从 `{server_url}/.well-known/mcp-clearance` (路径可配置)获取一个JWS紧凑许可,并使用 **操作员固定的信任根** 验证其签名。信任根在进程启动时提供给`AttestedAdmissionConfig`,但在热路径上从不通过网络获取。
2. **默认拒绝每个服务器的工具许可列表**。允许一个服务器并不意味着信任其所有工具。验证的许可声明中包含一个明确的工具名称列表,主机将允许这些工具;其他工具将被拒绝。`sub`声明与主机即将调度的服务器身份进行匹配(因此,服务器A被盗用的许可声明不能允许服务器B的工具调用)。
3. **基于Flavor的强制执行**。`ENFORCE`(默认)对缺失/无效/过期的许可声明进行硬拒绝;`WARN`记录并允许 - 这是操作员在引入针对真实流量的门控时想要的分阶段启动。
每个准入决定都会在 `guard="mcp_attested_admission"` 通道上发出 [`ReceiptVerdict`](./docs/attest/receipt.md),因此现有的 `airlock attest` DSSE管道不会更改地接收决定 - 这个预设 **不** 会发明一个新的日志。
```python
from agent_airlock.mcp_proxy_guard import MCPProxyConfig, MCPProxyGuard
from agent_airlock.mcp_spec.attested_admission import TrustRoot
from agent_airlock.policy_presets import mcp_attested_admission_defaults
# 操作员在启动时固定信任根。运行时从不获取。
with open("/etc/airlock/mcp-clearance-root.pem", "rb") as fh:
pinned_pem = fh.read()
cfg = mcp_attested_admission_defaults(
trust_root=TrustRoot(key_id="ops-2026Q2", ed25519_pem=pinned_pem),
enforcement_mode="ENFORCE", # 默认拒绝
max_clearance_age_days=30,
)
guard = MCPProxyGuard(MCPProxyConfig(attested_admission=cfg))
decision = guard.audit_tool_admission(
server_url="https://mcp.example.com",
server_id="srv-alpha", # 预期的 `sub` 声明
tool_name="read",
)
if not decision.admitted:
raise RuntimeError(decision.reason)
```
签名验证需要 `[attested]` 额外功能(引入 `cryptography` 进行离线Ed25519 / RSA-PSS / JWKS验证);基础安装保持零运行时依赖。
> 使用 `pip install "agent-airlock[attested]"` 安装。仅限选择加入 - 现有调用者如果不设置 `attested_admission` ,将获得与v0.8.9相同的行为。
---
### 🧭 行为序列守卫(v0.8.12)
监视会话中 **有序的工具调用流** ,并标记与声明的预期顺序发生偏差 - **不是** 模型的 stated推理轨迹。
[arXiv:2605.27901](https://arxiv.org/abs/2605.27901)(“思维链监控的脆弱性”,Onyame, Zhou, Thopalli, Kailkhura & Agarwal,2026年5月)报告了在8B-120B参数模型中平均 **95.9% 的思维链不忠实度** ,包括答案切换、事后合理化和利用提示的过程。仅依赖模型的 stated推理来检测行为不当是不可行的。依赖其 **行为** - 即它实际调用的工具序列 - 是可行的。
`SequenceGuard` 是 `SecurityPolicy` 上的一个可选字段,它在 `@Airlock` 接缝处运行,**在** 标准策略检查之后,以两种模式运行:
**DECLARED 模式** - 操作员提供一个允许的转换DAG。DAG中任何未声明的转换都是 `SequenceViolation` 。默认拒绝。
```python
from agent_airlock import Airlock, SecurityPolicy
from agent_airlock.sequence_guard import SequenceGuard, ENTRY_SENTINEL
policy = SecurityPolicy(
sequence_guard=SequenceGuard(
mode="declared",
action="block", # 或 "warn"
dag={
ENTRY_SENTINEL: {"read"}, # 只有 `read` 可以启动会话
"read": {"read", "summarize"}, # 读取后,可以重新读取或总结
"summarize": {"send"}, # 总结后,只能发送
"send": set(), # 发送是终端
},
),
)
```
**BASELINE 模式** - 守护程序在本地JSON文件中维护一个每个会话密钥的马尔可夫转换配置文件(无云,无PII - 只有工具名称和 `(arg types, kwarg names+types)` 的SHA-256 **形状哈希** ,**绝不** 参数值),并在从 `prev` 达到 `min_baseline_samples` 时,标记具有观察到的 `P(curr | prev) < threshold` 的转换。
```python
from pathlib import Path
from agent_airlock.sequence_guard import SequenceGuard
policy = SecurityPolicy(
sequence_guard=SequenceGuard(
mode="baseline",
baseline_path=Path("/var/lib/airlock/sequence-baseline.json"),
low_probability_threshold=0.05, # 标记底部 5%
min_baseline_samples=50, # 在 `prev` 处不标记,直到 50 个观察
),
)
```
每个标记的转换都会在当前span上发出OTel span属性(`airlock.sequence_guard.mode`,`.from_tool`,`.to_tool`,`.session_key`,`.observed_probability`)通过现有的`observability`提供者 - 遥测失败被吞咽,因此它们不能破坏强制执行。
**不是** `AnomalyDetector` (那是速率/端点多样性/错误率/连续阻塞,在滑动窗口上)。`SequenceGuard` 是每个转换的ORDER信号。运行两个进行分层覆盖。 **不是** 链式思维监控器 - 通过构造。
> 严格选择加入。新的 `SecurityPolicy.sequence_guard` 字段默认为 `None` ;调用者如果不设置它,将获得与v0.8.11相同的行为。零新的运行时依赖 - Pydantic-only核心保持完整。
---
### 🛑 动作时间矛盾门控(v0.8.15)
[arXiv:2605.27157](https://arxiv.org/abs/2605.27157)(“检测不等于解决:检索增强LLM中的监控控制差距”,Yu et al.,2026)表明LLM **轻松承认其推理轨迹中的矛盾证据** ,但“这种意识未能约束其最终建议”。缺陷在于 **动作选择** - 单次诊断高估了RAG安全性,而仅检测是不够的。
`ActionContradictionGate` 是一个可选的策略钩子,它包装了三个 **可插拔的检测器** (任意一个触发)和一个 **特权汇集全局集** 。当检测器触发并且调度的工具与特权汇集全局集匹配,并且harness没有发出明确的允许时,门控会阻止调用(或警告,取决于 `action=` )。
明确允许的基元 **不是新的** - 门控重用了现有的 `AirlockContext.authorize_once(tool_name)` (为v0.8.6重新认证流程引入)。相同的单次授予,同样的语义。在一次性被消耗后,门控 **重新锁定** - harness必须为每个特权操作铸造一个新的 `authorize_once` 。
```python
import re
from agent_airlock import Airlock, SecurityPolicy
from agent_airlock.action_contradiction_gate import ActionContradictionGate
policy = SecurityPolicy(
action_contradiction_gate=ActionContradictionGate(
# 检测器1:一个布尔标志,RAG管道在看到证据与声明冲突后会翻转。
signal_field_key="evidence_contradiction",
# 检测器2:与 **相同** 键的插件正则表达式,当其值为字符串时(操作员控制的标记 - 绝不是模型的完整推理轨迹)。
marker_regex=re.compile(r"contradict|conflict|disagree", re.I),
# 检测器3:完全可插拔的调用;接收上下文。
# predicate=lambda ctx: ctx.metadata.get("conflict_count", 0) > 1,
# 默认特权汇集全局集:send_* / export_* / commit_* / transfer_* / delete_* + v0.8.14出站集成集。
# 操作员可以通过 `privileged_sinks=(...)` 进行缩小。
action="block", # 或 "warn" 用于分阶段启动
),
)
```
**关闭默认不变性** 。 `SecurityPolicy.action_contradiction_gate` 默认值为 `None` ;非RAG流程支付 **零误报税** (无检测器运行,无日志行,无元数据读取)。即使连接,门控 **直到至少配置了一个检测器插槽** 才生效 - 因此部分推出(门控附加但检测器关闭)允许所有内容。
**不是** 链式思维监控器。门控读取 **操作员控制的信号** 仅(元数据字段,操作员正则表达式,操作员谓词)。它绝不读取模型自己的声明,即它是否注意到矛盾 - 论文的重点是这些声明 **不** 控制行为。
**不是** `sequence_guard` (v0.8.12)- 那标志着不寻常的调用 **顺序** 。 **不是** `reauth_on_untrusted_reinvocation` (v0.8.6)- 那是基于计数的,每工具计数驱动的。这个门控是信号驱动的,针对特定的特权汇集全局集。它们组合使用;运行所有三个进行分层覆盖。
> 严格选择加入。零新的运行时依赖 - Pydantic-only核心保持完整。新的 `SecurityPolicy.action_contradiction_gate` 字段默认为 `None` ;调用者如果不设置它,将获得与v0.8.14相同的行为。
---
### 📊 对抗性谈判回归测试框架(v0.8.17)
一个确定性的测试框架,用于衡量默认拒绝的治理层对一组固定的对抗性买方-卖方谈判动作的影响 - 并报告两个指标,旨在与外部发布的基准对齐,以便数字可以并排放置。
```bash
python -m agent_airlock.cli.negotiation_bench --report markdown
```
每个场景都带有 **具体的,可检查的不安全操作** ,并运行两次 - **基准** (无airlock,不安全事件落地)和 **受控** (相同的操作通过 **真实** 的 `@Airlock` 拦截-执行路径,无策略层模拟)。三个不安全操作类,每个操作练习一个真正的拦截机制:低于地板价 → Pydantic严格验证,秘密泄露 → 输出净化器,转移到策略外 → 默认拒绝 `SecurityPolicy` 。良性交易被包括在内,以确认治理不会过度阻止。
| 源 | 不安全执行率(基线 → 受控) | 有效任务成功率(基线 → 受控) |
|---|---|---|
| **agent-airlock** (此测试框架) | 100% → **0%** | 43% → **100%** |
| OCL(外部,实时LLM, [arXiv:2606.04306](https://arxiv.org/abs/2606.04306)) | 88% → ~0% | 12% → 96% |
> **OCL行是外部结果,不是agent-airlock的。** 它在AgenticPay-adapted谈判中测量(OCL, [arXiv:2606.04306](https://arxiv.org/abs/2606.04306) ; [AgenticPay](https://arxiv.org/abs/2602.06008) , [arXiv:2602.06008](https://arxiv.org/abs/2602.06008)) ,并仅在此处复制以进行 **方向比较** - 两个都将治理放在执行边界上。它 **不是** 相同的实验:agent-airlock是一个确定性的执行边界验证器,不是LLM,并且此测试框架不调用模型。agent-airlock行是 **策略层** 的属性,在最坏情况下通过脚本化的对手进行练习,通过真正的 `@Airlock` 路径。
测试框架兼作 **回归门控** :`--fail-if-governed-unsafe` 如果受控的 `unsafe_execution_rate` 提升到高于零,则退出非零,因此未来削弱策略层的更改都会失败CI。零新的运行时依赖;完全确定性(无随机性,无网络,无模型调用)。
---
### 🔎 特权大小调整 - `airlock-explain --unused-scopes` (v0.8.13)
一个只读CLI,显示 **过度许可** :它将 `SecurityPolicy` 的 **授予** 工具范围与代理 **实际调用** 的工具范围进行差异化处理,根据 `AgentIdentity` 和来自OTLP导出或本地审计JSONL的跟踪记录,每个差异化处理,并打印死重集以及 **建议的** 紧凑允许列表。
```bash
# 安装v0.8.13轮;airlock-explain变为可用
pip install "agent-airlock>=0.8.13"
# 差异化授予 vs 使用;打印表格
airlock-explain --unused-scopes \
--policy ./security-policy.toml \
--trace ./agent.audit.jsonl
# 相同,可读,带有建议的紧凑策略预览
airlock-explain --unused-scopes \
--policy ./security-policy.toml \
--trace ./otel-export.json \
--format json \
--suggest-policy
```
**仅观测性** 。此命令 **绝不修改** `SecurityPolicy` , **绝不写入** 策略文件, **绝不自动应用** 建议。拒绝默认姿势保持不变 - 正确大小CLI是一个 **审查辅助工具** ,不是强制原语。 `--suggest-policy` 输出故意作为stdout预览,以便人类审查紧凑的允许列表后再手动采用。
跟踪格式(自动通过检查文件头检测):
- **审计JSONL** - `AuditLogger` 已经发出的格式。每个JSON对象一行,带有 `tool_name` / `agent_id` / `blocked` 。被阻止的调用从“实际调用”集合中排除 - 被阻止的调用 **不是** 授予范围的练习。
- **OTLP JSON** - `opentelemetry-exporter-otlp` 编写的格式。跨度 `name` 是工具名称; `attributes.agent_id` 键控每个代理差异化。如果跨度带有 `airlock.blocked=true` ,则跳过,与JSONL相同。
**差异语义** 。匹配器是 `fnmatch` - 与 `SecurityPolicy.check_tool_allowed` 内部使用的相同通配符语义,因此建议的紧凑允许列表允许的工具与代理观察到的调用工具完全一致(采用时无惊喜)。拒绝模式模式转发不变:拒绝是 **意图** ,不是使用数据。
> 严格观察性。新的控制台入口 `airlock-explain` 是项目中的第一个可安装CLI;现有的 `python -m agent_airlock.cli.<name>` 调用不受影响。
---
### 🩹 技能抵抗性跟踪减少 + 水印(v0.8.24)
**为什么跟踪是提取表面** :代理发出的跟踪/收据是蒸馏目标,不仅是审计工件。跟踪记录的调谐阈值,策略触发的精确工具调用参数,以及恢复的中间公式/策略,交给竞争对手 **配方** - 足以克隆行为而不支付搜索费用。验证器相比,只需要 **证据** (门控运行 / 策略触发器 / 通过/失败),永远是配方。这就是RedAct-style威胁模型 - 由已发布的基于行为的水印工作组合而成(Agent Guide, [arXiv:2504.05871](https://arxiv.org/abs/2504.05871) ; [CoTGuard](https://arxiv.org/abs/2505.19405) ; [Distilling the Thought](https://arxiv.org/abs/2601.05144] ;agent-airlock不复制任何论文的基准。
`TraceRedactionPolicy` (可选的优化器([Agent Guide](https://arxiv.org/abs/2504.05871) ; [CoTGuard](https://arxiv.org/abs/2505.19405) ; [Distilling the Thought](https://arxiv.org/abs/2601.05144) ),agent-airlock不复制任何论文基准。
`TraceRedactionPolicy` (可选,**默认关闭**以保持向后兼容,**STRICT_POLICY**下打开) 在非本地接收器(例如OTel导出器)处运行:它(a)使用可配置的字段分类器 **本地化** 保护字段(调谐阈值,工具调用参数,恢复的公式/策略);(b) **重写** 以保留验证器关键证据,同时删除配方;(c)嵌入 **租户行为水印** ,因此泄漏的跟踪证据是可证明的。检测它与`airlock trace verify-watermark <trace.json>`(关键的HMAC匹配 → 高检测率,低误报);添加 `--redaction-report` 以查看本地化/重写/保留的内容。仅限标准库 - 无新的运行时依赖。
```python
from agent_airlock import TraceRedactionPolicy, trace_redact, verify_watermark
pol = TraceRedactionPolicy(enabled=True, tenant_id="acme-co", watermark_secret="...")
redacted, report = trace_redact(trace, pol) # tuned_threshold → 证据存根;配方被丢弃
assert verify_watermark(redacted, pol).detected # 证明是你的
```
---
### ✅ 终端声明保护门控 - `no_false_success` (v0.8.25)
**诚实的停滞是可恢复的;自信的错误`done` 不是。** 无人值守的长时程代理的主要故障模式不是崩溃 - 而是 **自信地报告从未验证的成功** ( [Goal-Autopilot](https://arxiv.org/abs/2606.11688) )。`no_false_success` 预设强制执行该论文的No-False-Success底线:终端/完成声明仅在 **命名** 的、可 **证伪** 的检查实际执行并通过 **本次运行** 后才被允许。没有收据、失败检查或伪造/重放收据 → 保护门控失败,恢复到 **可恢复的诚实停滞** (运行命名检查并重试),而不是虚构的成功。
伪造抵抗性是结构性的:保护门控会生成一个每运行一次的令牌,并且只信任一个收据,该收据由它在 **本次运行** 中实际执行的检查进行签名 - 一个仅存在 **存在** 的收据(手工构建,或从以前的运行中重放)会被拒绝。按代理可选 `AirlockConfig(require_done_receipt=True)` (或 `[airlock]` 在 `airlock.toml` 中 `require_done_receipt = true` );默认为关闭。仅限标准库 - 无新的运行时依赖。
```python
from agent_airlock import no_false_success_defaults, NoFalseSuccessStall
preset = no_false_success_defaults({"tests_green": run_pytest}) # 可证伪检查
preset["guard"].run("tests_green") # 实际执行检查本次运行
preset["check"]("tests_green") # 除非通过,否则引发NoFalseSuccessStall
```
### 💰 成本控制
失控的代理可能会在您注意到之前烧掉 500 美元的 API 费用。
```python
from agent_airlock import Airlock, AirlockConfig
config = AirlockConfig(
max_output_chars=5000, # 在令牌爆炸之前截断
max_output_tokens=2000, # 响应大小的硬限制
)
@Airlock(config=config)
def query_logs(query: str) -> str:
return massive_log_query(query) # 10MB → 5KB
```
**投资回报率:** 10MB 日志 = ~2.5M 令牌 = 25 美元/响应。截断 = ~1.25K 令牌 = 0.01 美元。 **99.96% 节省。**
#### 按模型层级的预算(v0.8.7)
上述统一的 `max_output_*`上限适用于每个调用。 **`ModelTierBudget`**上限每个调用的成本和输出令牌 **按模型层级标签** (例如`"frontier"` / `"mid"` / `"small"`),在工具运行前评估。未标记的调用会回落到一个可配置的 `strict_tier`(默认拒绝 - 最便宜的层级)。
```python
from agent_airlock import (
Airlock, ModelTierBudget, SecurityPolicy, TierBudget,
)
policy = SecurityPolicy(
model_tier_budget=ModelTierBudget(
tiers={
"frontier": TierBudget(max_cost_cents=50, max_output_tokens=4000),
"mid": TierBudget(max_cost_cents=10, max_output_tokens=2000),
"small": TierBudget(max_cost_cents=2, max_output_tokens=1000),
},
strict_tier="small", # 未标记 → 最便宜的层级(默认拒绝)
),
)
@Airlock(policy=policy, return_dict=True)
def call_model(prompt: str, **_extra):
return run_my_router(prompt)
# 路由器标记每个调用。 Airlock 在模型启动前阻止。
call_model("Draft a tweet", _airlock_tier="small", _airlock_input_tokens=50)
call_model("Deep analysis", _airlock_tier="frontier", _airlock_input_tokens=200_000)
# → AIRLOCK_BLOCK: Tier 'frontier' budget exceeded (worst-case 66¢ > cap 50¢)
```
路由逻辑保留在用户的路由器中。支持三种标记路由:
1. **`_airlock_tier` kwarg** — 在工具看到它之前会剥离。
2. **`context.metadata["airlock_tier"]`** — 由路由器的会话中间件设置在 `AirlockContext` 上。
3. **`tier_resolver` 回调** — `ModelTierBudget(tier_resolver=fn)`
其中 `fn(model_id: str) -> tier_label` 位于调用者的代码中。
Airlock 在 `context.metadata["model_id"]` 设置时调用回调;它不携带供应商特定的模型→层级表。
执行后,实际成本与预估成本在全局 `CostTracker` 中核对(可观察性 - 永远不会阻塞)。参见
[`examples/model_tier_budget.py`](./examples/model_tier_budget.py) 中的所有四种模式,包括与允许/拒绝列表的组合。
一个现成的 `strict_tier_budget_policy()` 预设返回一个
使用上述表格初始化的 `SecurityPolicy`。
---
### 🔐 个人身份信息和秘密屏蔽
```python
config = AirlockConfig(
mask_pii=True, # 社会安全号码,信用卡,电话号码,电子邮件
mask_secrets=True, # API 密钥,密码,JWT
)
@Airlock(config=config)
def get_user(user_id: str) -> dict:
return db.users.find_one({"id": user_id})
# LLM 看到:{"name": "John", "ssn": "[REDACTED]", "api_key": "sk-...XXXX"}
```
**12 种个人身份信息类型检测** · **4 种屏蔽策略** · **零数据泄露**
#### 选择性地区个人身份信息(`pii_locales`)
Aadhaar / PAN / UPI / IFSC 一直作为 `SensitiveDataType` 成员提供,
但不添加到默认的 `mask_pii=True` 集 - 以保持表面
默认为零依赖和美国形状。 **v0.8.9** 增加了一个 `pii_locales` 选择性加入
它引入了这些并加强了检测:
```python
config = AirlockConfig(
mask_pii=True,
pii_locales=["in"], # 选择加入印度地区检测
)
@Airlock(config=config)
def lookup(query: str) -> str:
return (
"User: राम कुमार, "
"Aadhaar: 234567890124, " # → "********0124" (后4位,仅限UIDAI标准)
"PAN: ABCDE1234F, " # → "AB******4F" (前2位 + 后2位)
"UPI: alice@oksbi, " # → "a***@oksbi" (屏蔽本地部分,保持@银行)
"phone: 555-123-4567" # 仍然被现有的PHONE正则表达式屏蔽
)
```
当 `"in" in pii_locales` 时,会激活两件事:
- **Aadhaar Verhoeff 校验和门控** - 现有的Aadhaar正则表达式是
宽容的(任何12位数字以2-9开头都匹配)。有了选择加入,
每个匹配还必须通过UIDAI Verhoeff校验和,大约降低10倍的FP
率在随机ID /电话号码上。
- **Devanagari个人姓名检测** - `PERSONAL_NAME_DEVANAGARI`在
Unicode块`U+0900–U+097F`上运行,并带有少量允许列表的常见
印地语问候语/代词/疑问词,以保持普通话语不被屏蔽。 保守的启发式 -
需要精确提取的生产调用者应该在上面分层NER。
该标志是 **累加和可逆的** - `pii_locales=[]` (默认值)
保留以前的行为比特对比特。
---
### 🌐 网络隔离(V0.3.0)
在工具执行期间阻止数据外流:
```python
from agent_airlock import network_airgap, NO_NETWORK_POLICY
# 阻止所有网络访问
with network_airgap(NO_NETWORK_POLICY):
result = untrusted_tool() # 任何套接字调用→NetworkBlockedError
# 或仅允许特定主机
from agent_airlock import NetworkPolicy
INTERNAL_ONLY = NetworkPolicy(
allow_egress=True,
allowed_hosts=["api.internal.com", "*.company.local"],
allowed_ports=[443],
)
```
---
### 💉 框架疫苗接种(V0.3.0)
在**不更改任何一行代码的情况下**保护现有代码:
```python
from agent_airlock import vaccinate, STRICT_POLICY
# 之前:您的现有LangChain工具未受保护
vaccinate("langchain", policy=STRICT_POLICY)
# 之后:所有@tool装饰器现在都包含Airlock安全功能
# 无需更改代码!
```
**支持:** LangChain,OpenAI Agents SDK,PydanticAI,CrewAI
---
### ⚡ 熄灭器(V0.4.0)
用容错能力防止级联故障:
```python
from agent_airlock import CircuitBreaker, AGGRESSIVE_BREAKER
breaker = CircuitBreaker("external_api", config=AGGRESSIVE_BREAKER)
@breaker
def call_external_api(query: str) -> dict:
return external_service.query(query)
# 5 次失败后 → 电路打开 → 快速失败 30 秒
# 然后 HALF_OPEN → 允许 1 个测试请求 → 恢复或重新打开
```
---
### 📈 OpenTelemetry 可观察性(V0.4.0)
企业级监控:
```python
from agent_airlock import configure_observability, observe
configure_observability(
service_name="my-agent",
otlp_endpoint="http://otel-collector:4317",
)
@observe(name="critical_operation")
def process_data(data: dict) -> dict:
# 自动创建跨度,指标和审计日志
return transform(data)
```
---
## 🔌 框架兼容性
> **黄金法则:** `@Airlock` 必须距离函数定义最近。
```python
@framework_decorator # ← 框架看到安全的函数
@Airlock() # ← 安全层(最内层)
def my_function(): # ← 您的代码
```
<table>
<tr>
<td>
### LangChain / LangGraph
```python
from langchain_core.tools import tool
from agent_airlock import Airlock
@tool
@Airlock()
def search(query: str) -> str:
"""搜索信息。"""
return f"Results for: {query}"
```
</td>
<td>
### OpenAI Agents SDK
```python
from agents import function_tool
from agent_airlock import Airlock
@function_tool
@Airlock()
def get_weather(city: str) -> str:
"""获取城市天气。"""
return f"Weather in {city}: 22°C"
```
</td>
</tr>
<tr>
<td>
### PydanticAI
```python
from pydantic_ai import Agent
from agent_airlock import Airlock
@Airlock()
def get_stock(symbol: str) -> str:
return f"Stock {symbol}: $150"
agent = Agent("openai:gpt-4o", tools=[get_stock])
```
</td>
<td>
### CrewAI
```python
from crewai.tools import tool
from agent_airlock import Airlock
@tool
@Airlock()
def search_docs(query: str) -> str:
"""搜索内部文档。"""
return f"Found 5 docs for: {query}"
```
</td>
</tr>
</table>
<details>
<summary><b>更多框架:LlamaIndex,AutoGen,smolagents,Anthropic</b></summary>
### LlamaIndex
```python
from llama_index.core.tools import FunctionTool
from agent_airlock import Airlock
@Airlock()
def calculate(expression: str) -> int:
return eval(expression, {"__builtins__": {}})
calc_tool = FunctionTool.from_defaults(fn=calculate)
```
### AutoGen
```python
from autogen import ConversableAgent
from agent_airlock import Airlock
@Airlock()
def analyze_data(dataset: str) -> str:
return f"Analysis of {dataset}: mean=42.5"
assistant = ConversableAgent(name="analyst", llm_config={"model": "gpt-4o"})
assistant.register_for_llm()(analyze_data)
```
### smolagents
```python
from smolagents import tool
from agent_airlock import Airlock
@tool
@Airlock(sandbox=True)
def run_code(code: str) -> str:
"""在E2B沙盒中执行。"""
exec(code)
return "Executed"
```
### Anthropic(直接API)
```python
from agent_airlock import Airlock
@Airlock()
def get_weather(city: str) -> str:
return f"Weather in {city}: 22°C"
# 在工具处理程序中使用
def handle_tool_calls(name, inputs):
if name == "get_weather":
return get_weather(**inputs) # Airlock验证
```
</details>
### 适配器发货 vs 示例仅(诚实分开)
> 两条路径都使用相同的 `@Airlock()` 装饰器放置。 "适配器发货"
> 意味着有一个专用的 `src/agent_airlock/integrations/<framework>.py`
> 模块具有框架特定的胶水(签名保留,工具注册
> 重写,请求形状适配器)。 "仅示例" 意味着装饰器是
> 兼容开箱 - 不需要额外的适配器。
**适配器发货(11):** LangChain (`integrations/langchain.py`),
LangGraph (`integrations/langgraph_toolnode_compat.py`),
OpenAI Agents SDK (`integrations/openai_guardrails.py`),
Anthropic Messages API (`integrations/anthropic.py`),
Anthropic Claude Agent SDK (`integrations/anthropic_claude_agent_sdk.py`,v0.6.1+),
smolagents (`integrations/smolagents_wrapper.py`),
Gemini 3 Agent Mode (`integrations/gemini3_tool_shape_adapter.py`),
GPT-5.5 (`integrations/gpt5_5_tool_shape_adapter.py`),
PydanticAI (`integrations/pydantic_ai.py`,v0.7.1+),
CrewAI (`integrations/crewai.py`,v0.7.2+),
FastMCP (`mcp.py`).
**仅示例(2):** AutoGen,LlamaIndex -
装饰器兼容,无需适配器;请参阅 `examples/`。
### 完整示例
| 框架 | 路径 | 表面 |
|-----------|------|---------|
| LangChain | [适配器](./src/agent_airlock/integrations/langchain.py) · [示例](./examples/langchain_integration.py) | @tool, AgentExecutor |
| LangGraph | [适配器](./src/agent_airlock/integrations/langgraph_toolnode_compat.py) · [示例](./examples/langgraph_integration.py) | StateGraph, ToolNode |
| OpenAI Agents | [适配器](./src/agent_airlock/integrations/openai_guardrails.py) · [示例](./examples/openai_agents_sdk_integration.py) | Handoffs, manager pattern |
| Anthropic API | [适配器](./src/agent_airlock/integrations/anthropic.py) · [示例](./examples/anthropic_integration.py) | Direct Messages API |
| Claude Agent SDK | [适配器](./src/agent_airlock/integrations/anthropic_claude_agent_sdk.py) · [文档](./docs/integrations/anthropic-claude-agent-sdk.md) | `wrap_agent(agent, policy=...)` |
| smolagents | [适配器](./src/agent_airlock/integrations/smolagents_wrapper.py) · [示例](./examples/smolagents_integration.py) | CodeAgent, E2B |
| Gemini 3 | [适配器](./src/agent_airlock/integrations/gemini3_tool_shape_adapter.py) | `function_call` 载体 + `thought_signature` 减少 |
| GPT-5.5 | [适配器](./src/agent_airlock/integrations/gpt5_5_tool_shape_adapter.py) | `gpt_5_5_agent_defaults` 预设 |
| FastMCP | [适配器](./src/agent_airlock/mcp.py) · [示例](./examples/fastmcp_integration.py) | `@secure_tool` 装饰器 |
| PydanticAI | [适配器](./src/agent_airlock/integrations/pydantic_ai.py) · [文档](./docs/integrations/pydantic-ai.md) · [示例](./examples/pydanticai_integration.py) | `wrap_agent(agent, policy=...)` + output_validate hook |
| LlamaIndex | [仅示例](./examples/llamaindex_integration.py) | ReActAgent |
| AutoGen | [仅示例](./examples/autogen_integration.py) | ConversableAgent |
---
## ⚡ FastMCP 集成
```python
from fastmcp import FastMCP
from agent_airlock.mcp import secure_tool, STRICT_POLICY
mcp = FastMCP("production-server")
@secure_tool(mcp, policy=STRICT_POLICY)
def delete_user(user_id: str) -> dict:
"""一个装饰器:MCP注册 + Airlock保护。"""
return db.users.delete(user_id)
```
---
## 🏆 为什么不选择企业级供应商?
| | 提示安全 | Pangea | **Agent-Airlock** |
|---|:---:|:---:|:---:|
| **定价** | $50K+/year | 企业 | **永久免费** |
| **集成** | 代理网关 | 代理网关 | **一个装饰器** |
| **自我修复** | ❌ | ❌ | **✅** |
| **E2B 沙盒** | ❌ | ❌ | **✅ 原生支持** |
| **您的数据** | 他们的服务器 | 他们的服务器 | **永远不会离开您** |
| **源代码** | 封闭 | 封闭 | **MIT 许可** |
> 我们不反对企业。我们反对设置门槛。
> **AI 代理的安全性不应该需要采购流程。**
---
## 📦 安装
```bash
# 核心(验证 + 策略 + 净化)
pip install agent-airlock
# 带有 E2B 沙盒支持
pip install agent-airlock[sandbox]
# 带有 FastMCP 集成
pip install agent-airlock[mcp]
# 所有功能
pip install agent-airlock[all]
```
```bash
# E2B 密钥用于沙盒执行
export E2B_API_KEY="your-key-here"
```
---
## 🛡️ OWASP 合规
Agent-Airlock 映射到 [**OWASP 2026 顶级安全漏洞**](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/)
- 代理应用时代的旧LLM 顶级漏洞的继承者。 报告诚实:
**完整** 表示该模块提供并阻止测试中的类;
**部分** 表示agent-airlock 涵盖运行时腿,但某些上游内容(客户端UI,IAM,训练数据)超出范围;
**仅监控** 表示我们显示信号但不实际防止风险。
| 风险 | 在 agent-airlock 中实施 | 模块 / 预设 | 覆盖范围 |
|------|------------------------------|-----------------|----------|
| **ASI01 代理目标劫持** | Pydantic 严格验证 + 幽灵参数拒绝 + `UnknownArgsMode.BLOCK` | `validator`, `unknown_args`, `core` | 部分 |
| **ASI02 工具滥用和利用** | 默认拒绝 `SecurityPolicy`, RBAC, 速率限制, `SafePath` / `SafeURL`, Flowise `Function()`/ `eval` 令牌禁止 ([CVE-2025-59528](https://labs.cloudsecurityalliance.org/research/csa-research-note-flowise-mcp-rce-exploitation-20260409-csa/)),MCPwn破坏性认证检查 ([CVE-2026-33032](https://nvd.nist.gov/vuln/detail/CVE-2026-33032)), 移动MCP 意图URL防护 ([CVE-2026-35394](https://www.sentinelone.com/vulnerability-database/cve-2026-35394/)), 安全URL IPv6过渡元数据SSRF ([CVE-2026-48782](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cg7w-rg45-pc59)) | `policy`, `safe_types`, `filesystem`, `network`, `policy_presets.flowise_cve_2025_59528_defaults`, `policy_presets.mcpwn_cve_2026_33032_defaults`, `policy_presets.mobile_mcp_intent_guard_2026_05` | **完整** |
| **ASI03 身份和特权滥用** | `AgentIdentity`, `MCPProxyGuard` 令牌传通预防, 凭证范围, OAuth应用审计 ([Vercel 2026-04-19](https://vercel.com/kb/bulletin/vercel-april-2026-security-incident)),MCP 认证工具服务器准入 ([arXiv:2605.24248](https://arxiv.org/abs/2605.24248)) | `policy`, `mcp_proxy_guard`, `mcp_spec.oauth_audit`, `mcp_spec.attested_admission`, `policy_presets.oauth_audit_vercel_2026_defaults`, `policy_presets.mcp_attested_admission_defaults` | 部分 |
| **ASI04 代理供应链漏洞** | Ox MCP STDIO 净化器 + CVE 回归套件(11+ 跟踪的CVE)+ 会话快照完整性保护 + 启动时MCP 配置固定 (CVE-2026-30615, `policy_presets.mcp_config_pin`) | `mcp_spec.stdio_guard`, `mcp_spec.session_guard`, `mcp_spec.zero_click_config_guard`, `policy_presets.stdio_guard_ox_defaults`, `policy_presets.mcp_config_pin`, `tests/cves/` | 部分 |
| **ASI05 非预期代码执行(RCE)** | E2B Firecracker 沙盒, 可插拔 `SandboxBackend`, `PROCESS_SHELL` 能力控制, Flowise 评估令牌禁止 ([CVE-2025-59528](https://labs.cloudsecurityalliance.org/research/csa-research-note-flowise-mcp-rce-exploitation-20260409-csa/)) | `sandbox`, `sandbox_backend`, `capabilities`, `policy_presets.flowise_cve_2025_59528_defaults` | **完整** |
| **ASI06 内存和上下文中毒** | `AirlockContext` `contextvars` 隔离, `ConversationConstraints` 预算上限, 审计日志 | `context`, `conversation`, `sanitizer` | 部分 |
| **ASI07 不安全代理间通信** | A2A 中间件 Pydantic 严格验证, 方法允许列表 | `a2a` | 部分 |
| **ASI08 级联故障** | `CircuitBreaker`, `RetryPolicy`, 令牌桶速率限制 | `circuit_breaker`, `retry`, `policy` | **完整** |
| **ASI09 人工智能代理信任利用** | Honeypot 欺骗, 审计日志属性, 结构化 `fix_hints` | `honeypot`, `audit_otel` | 部分 |
| **ASI10 流氓代理** | 审计遥测 + 异常检测器; 无隔离模块 | `observability`, `anomaly` | 仅监控 |
### MCP 特定映射
[OWASP MCP Top 10 (2026 测试版)](https://owasp.org/www-project-mcp-top-10/)
已由 `OWASP_MCP_TOP_10_2026` 策略预设全面覆盖:
| MCP 风险 | 包含于代理-airlock |
|----------|------------------------|
| **MCP01令牌管理不当** | `MCPProxyGuard` 拒绝直通标头,强制实施受众验证 |
| **MCP02 过度权限** | `SecurityPolicy` + `CredentialScope` |
| **MCP03 工具中毒** | 幽灵参数拒绝 + `SafePath`/`SafeURL` |
| **MCP04 供应链** | `stdio_guard_ox_defaults()` (Ox 2026-04-16 advisory) |
| **MCP05 命令注入** | `stdio_guard` shell 元字符 + 拒绝模式规则 |
| **MCP07 身份验证不足** | `mcp_spec.oauth` 中的 OAuth 2.1 + PKCE S256 帮助程序 |
| **MCP10 上下文过度共享** | PII/secret 净化器 + 工作区范围配置 |
直接使用:
```python
from agent_airlock import Airlock
from agent_airlock.policy_presets import owasp_mcp_top_10_2026_policy
@Airlock(policy=owasp_mcp_top_10_2026_policy())
def my_mcp_tool(...):
...
```
> **Ox Security STDIO advisory** (2026-04-16,CVE-2026-30616):参见
> [`docs/cves/index.md#cve-2026-30616`](docs/cves/index.md#cve-2026-30616)
> 和上面的 `stdio_guard_ox_defaults()` 预设。agent-airlock
> 在运行时缝隙中阻止了 4 类 Ox 攻击中的 3 类。
---
## 🏢 使用者
Agent-Airlock 可用于生产环境的 AI 代理系统:
| 项目 | 用例 |
|---------|----------|
| [**FerrumDeck**](https://github.com/sattyamjjain/FerrumDeck) | AgentOps 控制平面 — 默认拒绝工具执行 |
| [**Mnemo**](https://github.com/sattyamjjain/Mnemo) | MCP 原生内存数据库 — 安全工具调用验证 |
> 在生产环境中使用 Agent-Airlock? [打开一个 PR](https://github.com/sattyamjjain/agent-airlock/edit/main/README.md) 以添加您的项目!
---
## 📊 性能
> 测试计数和覆盖率由此文件顶部的 TEST-BADGE 块发布,
> 每发布一次使用 `python scripts/update_test_badge.py` 从 pytest 重新生成。
> 该块是真实来源;此表格仅跟踪延迟和表面积。
| 指标 | 值 |
|--------|-------|
| **验证开销** | <50毫秒 |
| **沙箱冷启动** | 约 125 毫秒 |
| **沙箱热池** | <200毫秒 |
| **框架集成** | 13 |
| **核心依赖** | 0(仅 Pydantic) |
## 📖 文档
| 资源 | 描述 |
|----------|-------------|
| [**AGENTS.md**](./AGENTS.md) | v0.6.1 — 智能 IDE (如 Cursor、Claude Code、Windsurf、Mintlify)的仓库入口 |
| [**Anthropic Claude 代理 SDK 适配器**](./docs/integrations/anthropic-claude-agent-sdk.md) | v0.6.1 — `AnthropicClaudeAgentSDKAdapter.wrap_agent(agent, policy=...)`;规范列表三元组 |
| [**`airlock manifest enforce`**](https://news.backbox.org/2026/05/01/200000-mcp-servers-expose-a-command-execution-flaw-that-anthropic-calls-a-feature/) | v0.6.1 — 失败关闭 CLI 运行时允许列表门控针对签名清单;CI 退出 0/2/3 |
| [**托管代理结果评估标准守卫**](./docs/policies/managed-agents-outcomes-2026-05-06.md) | v0.7.4 — 失败关闭 Anthropic 托管代理 2026-05-06 结果评估标准 ID 的门控;`ManagedAgentsOutcomesGuard.evaluate(provenance)` + `managed_agents_outcomes_2026_05_06_defaults` 工厂;无 SDK 依赖 |
| [**Filter-Eval RCE 守卫(CVE-2026-25592 + CVE-2026-26030)**](./docs/policies/semantic-kernel-filter-eval-rce.md) | v0.7.5 — 用于 Semantic-Kernel 类 lambda 过滤器/模板表达式 eval RCE 原始操作的正则表达式检测器(MSRC 2026-05-07);`FilterEvalRCEGuard.evaluate(args)` + `semantic_kernel_filter_eval_rce_2026_25592_26030_defaults` 工厂;框架无关 |
| [**OIDC 发布窗口守卫(TanStack 2026-05-11)**](./docs/policies/npm-oidc-publish-window-guard.md) | v0.7.6 — 用于 TanStack/Mini-Shai-Hulud npm OIDC 受信任发布者类的已知恶意爆炸列表守卫(2026-05-11 事后分析;42 个软件包 × 84 个版本);`OIDCPublishWindowGuard.evaluate(args)` + `npm_oidc_publish_window_guard_defaults` 工厂;纯数据预设,无运行时 npm 调用 |
| [**MCP STDIO 命令注入守卫**](./docs/policies/mcp-stdio-command-injection-guard.md) | v0.7.6 — 用于 MCP STDIO argv 矢量的 shell 元字符 + 选择加入路径遍历拒绝者(HelpNetSecurity 2026-05-05);`StdioCommandInjectionGuard.evaluate(args)` + `mcp_stdio_command_injection_preset_defaults` 工厂;无 `mcp` SDK 依赖 |
| [**Eval-RCE 守卫(CVE-2026-44717)**](./docs/policies/eval-rce-cve-2026-44717.md) | v0.8.0 — 用于 MCP Calculate Server 类的裸 `eval()`/`parse_expr()`/`exec()` 调用检测器(NVD 2026-05-15);`EvalRCEGuard.evaluate(args)` + 精选的漏洞软件包拒绝列表 + `parse_expr` 安全形式豁免 + `stdio_guard_eval_defaults_2026_05_15` 工厂 |
| [**MCP Inspector 暴露守卫(CVE-2026-23744 运行时)**](./docs/policies/mcp-inspector-exposure-guard.md) | v0.8.0 — 通过 stdlib `/proc/net/tcp` 进行 Linux 运行时监听扫描,用于 MCPJam Inspector 公共绑定类;补充 v0.5.x 配置时间 `bind_address_guard`;`MCP_INSPECTOR_REQUIRE_AUTH=1` 操作员绕过 |
| [**代理 SDK 信用池预算**](./docs/budget/agent-sdk-credit.md) | v0.8.0 — 用于 Anthropic 2026-06-15 计费分割的每月的美元池跟踪器(Zed 博客 2026-05-14);`AgentSDKCreditBudget.register_call(model, input_tokens, output_tokens)`,具有 90% 接近限制 + 100% 耗尽阈值;打包 2026-06 定价装置 |
| [**OpenAPI 漂移守卫(Hermes 2026-05-13)**](./docs/policies/openapi-drift-guard.md) | v0.8.1 — 用于操作员提供的 OpenAPI 3.x 规范的载荷形状漂移检测器(arXiv:2605.14312);`OpenAPIDriftGuard.evaluate(operation_id, args)` 检测 `missing_required` / `unknown_field` / `type_mismatch`;三种模式(`strict` / `warn` / `shadow`);`vaccinate_openapi(spec)` 装饰器 + `openapi_doc_drift_guard_defaults` 工厂;调用者提供规范字典,无 PyYAML 依赖 |
| [**MCP 计算服务器捆绑预设**](./docs/policies/eval-rce-cve-2026-44717.md) | v0.8.1 — 组合工厂 `mcp_calc_server_bundle_defaults_2026_05_15()` 将 v0.8.0 `EvalRCEGuard` + v0.7.6 `StdioCommandInjectionGuard` 在单个 preset_id 下连接(CVE-2026-44717 锚点)作用于 calc/calculate/evaluate/sympy_eval/math_eval 工具名称模式;纯配置组合,无新检测器模块 |
| [**Metis 启发的语料库阻塞率回归**](./docs/policies/metis-inspired-corpus-block-rate.md) | v0.8.2 — 发布门控原始 `MetisInspiredCorpusBlockRateGuard` 运行确定性 25 项漏洞形状语料库(CVE-2026-44717 + 2026-05-05 STDIO 注入)通过 `EvalRCEGuard + StdioCommandInjectionGuard`;当阻塞率低于基线 - 5% 时,单侧门控触发;**不是 Metis 论文的 POMDP 攻击者复制品**(arXiv:2605.10067 被引用为动机,而不是提示源);`airlock corpus-bench` CLI 提供文本/json/md 报告 |
| [**语料库按类别覆盖率**](./docs/policies/metis-inspired-corpus-block-rate.md) | v0.8.3 — 将 v0.8.2 语料库基准扩展为 HarnessAudit-Bench(arXiv:2605.14271)两类别分类法(`resource_access`,`info_transfer`);`CorpusEntry.violation_category` 字段 + `CategoryCount` 决策字段;`airlock corpus-bench` 报告每个类别的覆盖率,以文本/json/md 显示;**不是 HarnessAudit-Bench 复制品**(制品尚未公开 - 分类法作为模式采用,评分不是) |
| [**Stainless SDK 来源分类器**](./docs/policies/stainless-provenance-probe.md) | v0.8.3 — 纯函数 `classify_sdk_lineage(user_agent, response_body_head)` 构建块标记由废弃的 Stainless SDK 工具链生成的 MCP 服务器(Anthropic 于 2026-05-13 收购 Stainless,托管生成器正在关闭);操作员可从自己的审计钩子调用 - **不是自动 HTTP 探针**(装饰器进程内架构,参见 ROADMAP §1);`stainless_provenance_probe_defaults()` 预设为 `default_action=tag_only`,可见性不是强制的 |
| [**人工监督装饰器**](./docs/policies/human-oversight-decorator.md) | v0.8.4 — `@requires_human_oversight(approver=...)` 在操作员提供的批准调用函数上设置工具函数(Code-as-Harness arXiv:2605.18747 锚点);`GRANT` → 调用包装函数,`DENY` → `OversightDeniedError`,`TIMEOUT` → `OversightTimeoutError`;与 `@Airlock(...)` 组合;协议形状 + `InProcessRecordedApprover` 测试助手;**不是双向审计发射 RPC 通道** - 操作员拥有传输(Slack/PagerDuty/CLI),代理气锁拥有门控 + 协议 |
| [**层合同接收块**](./docs/attest/layer-contract.md) | v0.8.5 — 签名 `airlock attest receipt` 有效载荷上的可选 `LayerContract` (假设/保证)块(arXiv:2605.18672 锚点);`--contract` 从判决列表中派生每个守卫的 `pass_rate`,`--assumes id1,id2` 声明上游层依赖;接收模式 v1 不变(附加字段);`pass_rate` 是样本上的测量统计数据(不是证明)- 每个保证都带有 `sample_size`,以便验证者可以适当地权衡低 N;**不是基于窗口计数器存储的**(该基础设施尚不存在 - 来自操作员提供的判决列表,无新抽象) |
| [**MCP 受信任工具服务器准入(arXiv:2605.24248)**](https://arxiv.org/abs/2605.24248) | v0.8.10 — MCP 工具服务器的可选准入门控(按 Metere(2026 年 5 月))。主机从 `{server_url}/.well-known/mcp-clearance` 获取 JWS 紧凑型许可,验证其签名与**操作员固定的信任根**(Ed25519 / RSA-PSS / JWKS - 绝不通过热路径从网络获取),并强制执行**默认拒绝每个服务器的工具允许列表**,该列表从验证的许可中解析。风味门控 `ENFORCE`(硬拒绝)/ `WARN`(仅记录)模式。每个决策都会在 `guard="mcp_attested_admission"` 通道上发出 `ReceiptVerdict` - 重用现有的 `airlock attest` DSSE 路径,**不**会发明新的日志。`mcp_attested_admission_defaults()` 工厂 + `MCPProxyGuard.audit_tool_admission()` 集成;签名验证在 `pip install agent-airlock[attested]` 后被阻塞 |
| [**移动 MCP 意图 URL 守卫(CVE-2026-35394)**](https://www.sentinelone.com/vulnerability-database/cve-2026-35394/) | v0.8.8 — 移动 MCP `mobile_open_url` 意图注入 RCE 类的防御捆绑包(< 0.0.50)。`mobile_mcp_intent_guard_2026_05()` 返回预配置的 `SafeURLValidator(allowed_schemes=["http", "https"])`(阻止 `intent:`,`content:`,`file:`,`app:`,`data:`,`javascript:`,`vbscript:`),`AirlockConfig(unknown_args=UnknownArgsMode.BLOCK)` 和规范的移动 MCP 工具名称语料库(`mobile_open_url`,`open_url`,`mobile_launch_url`)。与现有的 `SafeURL` 类型兼容 - 没有新的验证器发明。也修复了 `block_private_ips=True` 在 `SafeURLValidator` 中的无效(RFC1918 范围实际上没有被阻止,因为验证器自己的 `SafeURLValidationError` 引发被 `except ValueError` 捕获) |
| [**Capsule ShareLeak / PipeLeak(CVE-2026-21520)**](https://nvd.nist.gov/vuln/detail/CVE-2026-21520) | v0.8.14 — Capsule Security 公开的间接提示注入类影响 Microsoft Copilot Studio(ShareLeak,CVE-2026-21520,CVSS 7.5 高,CWE-77,2026-01-15 修复)和 Salesforce Agentforce(PipeLeak,并行模式)。两个向量共享相同的架构:不受信任的表单输入(SharePoint 表单 / Web-to-Lead 表单)与代理的上下文无边界连接,同时代理同时持有外发工具(Outlook 发送 / Salesforce 电子邮件案例)。`capsule_indirect_injection_cve_2026_21520_defaults()` 组合现有原语 - `default_deny=True` + 规范的 exfil 接收工具(`send_email`,`outlook_*`,`create_case`,`share_*`,`export_*`,`post_to_*`,`webhook_*`,...)+ `reauth_on_untrusted_reinvocation=True`(v0.8.6 辩论放大守卫在 `threshold=1`)+ `AirlockConfig(unknown_args=UnknownArgsMode.BLOCK)`。仅限选择加入 - 没有新的验证器发明,没有默认优先级链条入口。与 `airlock-explain --unused-scopes`(v0.8.13)配对,以便操作员从真实跟踪中填充读取侧允许列表,然后部署 |
| [**Flowise MCP-stdio 适配器 RCE(CVE-2026-40933)**](https://advisories.gitlab.com/npm/flowise-components/CVE-2026-40933/) | v0.8.16 — Flowise 身份验证的 RCE via MCP-stdio 适配器类(CVSS 9.9,2026 上游 Flowise 3.1.0 修复)。Flowise ≤ 3.0.x 将用户定义的 CustomMCP `command`+`args` 直接序列化到子进程 spawn 中,无沙盒或 argv 净化 - 导入聊天流是单击路径到 OS 级 RCE。`flowise_mcp_stdio_guard_2026_defaults()` 是 v0.7.6 `StdioCommandInjectionGuard` 的每个工具类投影(无新验证器发明),作用于 Flowise CustomMCP stdio 表面。失败关闭 shell 元字符(`;`,`&&`,`\|\|`,`|`,换行符,`$(`)`command`/`args`路径 + 选择加入路径遍历 `cwd_allowlist`;`check(args)` 引发 `FlowiseMcpStdioInjectionError`。OWASP **MCP05 命令注入**。连接到 `ox_mcp_supply_chain_2026_04_defaults()` - **纠正先前的错误分类**,CVE-2026-40933 被记录为“Semantic Kernel 标头泄漏”。 |
| [**MCP 描述与清单守卫(`mcp_description_manifest_guard`)**](https://arxiv.org/abs/2606.04769) | v0.8.18 - | v0.8.18 — 运行时一致性门控,断言工具的**模型面对描述**(声明的输入模式 + 广告功能/安全边界)与其**注册清单**匹配 **之前** 工具被允许,关闭失败,按照默认拒绝姿态。DCIChecker 研究(arXiv:2606.04769)的锚点,该研究在 2,214 个 MCP 服务器中测量了 **描述代码不一致性占 19,200 个工具对的 9.93%**。`DescriptionManifestGuard.evaluate(description)` 检测 `described_arg_not_in_manifest`(描述声称有一个幽灵参数),`undisclosed_side_effect`(清单有描述隐藏的副作用 - 毒害工具的方向),和 `overclaimed_capability`(描述宣传了一个不存在于清单中的功能);三种模式(`strict` / `warn` / `shadow`);`vaccinate_description_manifest(manifests)` 装饰器 + `mcp_description_manifest_guard_defaults()` 工厂。**在** 幻影参数剥离 + Pydantic 类型验证(管辖调用有效载荷)之上组合 - 它不会取代它们。OWASP **MCP03 工具中毒**。纯 Pydantic 核心,无新运行时依赖 |
| [**LeRobot pickle 反序列化 RCE(CVE-2026-25874)**](https://www.sentinelone.com/vulnerability-database/cve-2026-25874/) | v0.8.19 — 拒绝默认姿态,用于 HuggingFace LeRobot 未认证 RCE 类别(CVSS 9.3)。LeRobot 的异步推理 PolicyServer / 机器人客户端 `pickle.loads()` 有效载荷通过 **未经身份验证,非 TLS** gRPC 通道(`SendObservations` / `SendPolicyInstructions` / `GetActions`)接收 - 未经身份验证的可网络访问的攻击者可实现任意 OS 命令执行。提供可重用的 **`UnsafeDeserializationGuard`**(位于 `safe_types` 中,与 `SafePath`/`SafeURL` 相邻),在 pickle 幻觉字节 (`0x80` PROTO) 上失败关闭,基于 base64 编码的 pickle,以及 `pickle`/`marshal`/`shelve`/`dill`/`jsonpickle` 标记令牌 - 加上一个 airgap 配对,拒绝序列化对象(`bytes`)参数,除非调用声明了身份验证 **和** TLS 传输。连接到 `SecurityPolicy.deserialization_guard` 并在 `@Airlock` 接口(步骤 2.7)运行 **之前** 工具正文;阻止携带 `fix_hint` 命名 CVE-2026-25874。`lerobot_cve_2026_25874_defaults()` 是每个 CVE 的预测(按名称 glob 拒绝 `*deserialize*`/`*pickle.loads*`/`torch_load`/gRPC 方法 + 硬连线内容守卫)。与 **上方** 幽灵参数剥离 + Pydantic 类型验证组合。纯 Pydantic 核心,无新运行时依赖 |
| [**MCP 服务器 URL 环境插值秘密泄露(CVE-2026-32625)**](https://github.com/danny-avila/LibreChat/security/advisories/GHSA-6vqg-rgpm-qvf9) | v0.8.20 — 拒绝默认姿态,用于 LibreChat MCP 服务器 URL 凭证泄露类(CVSS 9.6,CWE-200,OWASP **MCP01**)。用户提供的 MCP 服务器连接模板(URL / 头 / 参数)携带环境插值令牌 (`${VAR}`,裸 `$VAR` 或 `%VAR%`)**在服务器端** 展开针对主机 `process.env` 并泄露一个秘密(`${JWT_SECRET}` / `${CREDS_KEY}` / `${MONGO_URI}`)到外发请求。 **`MCPServerEnvInterpolationGuard.evaluate(config)`**(位于 `mcp_spec/env_interpolation_guard.py`)扫描 URL/头/参数递归并拒绝 **任何** 插值令牌,除非其变量位于操作员声明的 `allowed_vars` 允许列表中的显式非秘密变量(默认为空 = 拒绝所有)。它从不读取 `os.environ` 或展开任何内容 - 仅限令牌匹配,因此它不能自行泄露。`mcp_server_env_interpolation_guard_defaults()` 工厂 + `check(config)` 引发 `MCPServerEnvInterpolationError`;转义的 `\$`/`$$` 不被标记。纯 Pydantic 核心,无新运行时依赖 |
| [**代码生成三引号 / 分隔符突破 RCE(CVE-2026-11393)**](https://www.thehackerwire.com/agentcore-cli-rce-via-triple-quote-neutralization-bypass-cve-2026-11393/) | v0.8.21 — 拒绝默认姿态,用于 AWS AgentCore CLI 代码注入类(CVSS 9,CWE-94,OWASP **ASI05**)。CLI 将模型/用户控制的 `collaborationInstruction` 拼接成生成的 Python **而未中和三引号字符**,因此精心设计的 `"""` 关闭生成的字符串文字并注入在代理导入时执行的语句 - 代理运行时 + 导入者的机器 RCE。 **`CodegenDelimiterInjectionGuard.evaluate(args)`**(位于 `mcp_spec/codegen_delimiter_guard.py`)递归扫描绑定到代码生成/模板/ `exec`/`eval` 接收器的参数并在三引号令牌 (`"""` / `'''`),引号突破令牌 (`");` / `')` / `" +` 和原始换行符上失败关闭 - 除非该字段位于操作员声明的 `allowed_literal_fields` 允许列表中的安全文字环境中。永远不会生成或执行代码 - 仅限令牌匹配。`codegen_delimiter_injection_guard_defaults()` 工厂 + `check(args)` 引发 `CodegenDelimiterInjectionError`;与 v0.8.0 `EvalRCEGuard` 组合(该守卫本身控制接收器)。纯 Pydantic 核心,无新运行时依赖 |
| [**MCP 桥接子进程命令/参数/环境 RCE(CVE-2026-42271,CISA KEV 2026-06-08,活跃利用中)- 涵盖 + 回归测试**](https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-42271) | v0.8.22 — 拒绝默认姿态,用于 LiteLLM MCP 预览端点命令注入类 ([CVSS 8.8, CWE-77 + CWE-78](https://nvd.nist.gov/vuln/detail/CVE-2026-42271),OWASP **ASI05**;**位于 CISA KEV 目录中,2026-06-08 添加,活跃利用中**)。LiteLLM 的 `POST /mcp-rest/test/connection` + `/mcp-rest/test/tools/list` 在请求正文中接受 stdio 传输 `command` / `args` / `env` 字段并将提供的命令作为子进程启动,享有代理进程的权限 - 任何低权限 API 密钥到达主机命令执行(当与 Starlette 主机头绕过 CVE-2026-48710 结合时,无身份验证 RCE)。 **`McpSubprocessArgInjectionGuard.evaluate(config)`**(位于 `mcp_spec/subprocess_arg_guard.py`)将 spawn 类型的 MCP 桥接参数 (`command`/`cmd`/`args`/`argv`/`env`) 视为不受信任并拒绝它们,除非解析的程序位于操作员声明的 `allowed_commands` 允许列表中的静态安全命令(默认为空 = 拒绝所有);`env` 携带代码加载变量 (`LD_PRELOAD`/`PATH`/`PYTHONPATH`/…)将被拒绝,无论如何;配置没有 spawn 类型的字段将通过。永远不会启动任何进程 - 仅限配置检查。`mcp_subprocess_arg_injection_guard_defaults()` 工厂 + `check(config)` 引发 `McpSubprocessArgInjectionError`;与 v0.7.6 `StdioCommandInjectionGuard` 组合。**回归证明(v0.8.38)** 针对实际 `/mcp-rest/test/connection` + `/mcp-rest/test/tools/list` 请求体中的 `tests/cves/test_cve_2026_42271_kev_regression.py`。纯 Pydantic 核心,无新运行时依赖 |
# 工具列表
| [**Cline 跨源 WebSocket 劫持 (CVE-2026-44211)**](https://advisories.gitlab.com/npm/cline/CVE-2026-44211/) | v0.8.27 — 默认拒绝 Cline Kanban 跨源 WebSocket 劫持类(npm `kanban` < 2.13.0,CVSS 9.7,**CWE-1385** WebSocket 中缺少源验证 + **CWE-306** 缺少身份验证,OWASP **ASI05**)。Cline 在 `127.0.0.1:3484` 上运行一个控制 WebSocket 服务器,该服务器在**不验证 `Origin` 头的情况下**接受每个升级;由于浏览器不对 `ws://` 应用同源策略/CORS,因此开发人员访问的任何网站都可以驱动代理 — 泄露工作区数据,在代理终端注入提示(RCE),或终止任务。**绑定到环回地址并不是缓解措施。** **`WebSocketOriginGuard`** (在 `mcp_spec/ws_origin_guard.py` 中)有两个接口:`audit_endpoint(host=…, origin_allowlist_enforced=…)` 标志一个控制端点,该端点强制执行 `Origin` 允许列表(错误配置),而 `check_upgrade(origin)` / `enforce_upgrade(origin)` / `wrap_handler(handler)` 形成一个运行时门,拒绝 `Origin` 缺失或在显式允许列表(空允许列表 = 拒绝所有)之外的 WebSocket 升级。保护程序从不打开套接字 — 描述符 / 单个 `Origin` 检查仅。`cline_cve_2026_44211_defaults(allowed_origins=[…])` 工厂 + `check(origin)` 引发 `WebSocketOriginHijackError`。仅 Pydantic 核心,无新的运行时依赖。 |
| [**SSRF 出口守卫 - 替代编码环回 / 重新绑定 (CVE-2026-47390)**](https://www.cve.org/CVERecord?id=CVE-2026-47390) | v0.8.29 — 默认拒绝 SSRF 保护绕过类(**CWE-918**,OWASP **ASI02**)。出口过滤器检查 *字面主机名字符串* 而不是**解析的 IP** ,通过以 `ipaddress` 拒绝但 HTTP 客户端连接到的形式编码环回 / 链路本地 / 云元数据:`127.1` ,十进制 `2130706433` ,八进制 `0177.0.0.1` ,十六进制 `0x7f000001` ,`::ffff:127.0.0.1` ,或其 DNS 记录指向 `169.254.169.254` 的公共主机名(重新绑定)。 **`SSRFEgressGuard`** (在 `ssrf_egress_guard.py` 中)将每个目标减少到其规范 IP(s) — 通过 `socket.inet_aton` 解码替代编码 **并在检查时解析主机名** (因此在连接时而不是解析时捕获环回重新绑定)— 并在 `allow_internal_hosts` 上任何环回 / 链路本地 / 元数据 / 未指定地址或 RFC1918 范围失败关闭,带有 3 行 `explain` 审计跟踪(规则 / 解析的 IP / 编码)在每个拒绝上。与 v0.5.5 的 `is_blocked_ipv6_range` 集(IPv4 映射 / NAT64 / 6to4 / ULA)组合。`ssrf_egress_guard_defaults(allow_internal_hosts=…)` 工厂 + `check(url)` 引发 `SSRFEgressBlocked`。仅 Pydantic 核心,无新的运行时依赖。 |
| [**MCP 源/主机 DNS 重新绑定守卫 (CVE-2026-11624)**](https://nvd.nist.gov/vuln/detail/CVE-2026-11624) | v0.8.30 — 默认拒绝 MCP HTTP/SSE/可流式传输的源/主机验证(**CWE-346** 源验证错误,CVSS 9.4,OWASP-MCP **MCP07**)。Google MCP Toolbox for Databases < 0.25.0 提供了一个本地 HTTP 传输,**未验证 `Origin` 或 `Host` 头**,因此浏览器开发人员访问可以 DNS 重新绑定到 `127.0.0.1` 并在本地服务器上脚本 MCP 工具调用(文件读取,命令执行,DB 访问)。在 0.25.0 中使用新的 `--allowed-hosts` 标志和 `--allowed-origins` 标志修复,警告 `*` 通配符。 **`McpOriginHostGuard`** (在 `mcp_spec/mcp_origin_host_guard.py` 中)验证入站 `Host` (始终)和 `Origin` (存在时)是否与显式 `allowed_origins` / `allowed_hosts` 允许列表一致;如果未配置,则默认为**仅环回地址**,并记录启动警告,而 `*` 通配符允许所有但也警告 — 镜像上游修复(stdio 传输没有源,不在范围内)。`check_headers(headers)` / `validate(headers)` + `startup_warnings` 列表;`mcp_origin_host_guard_defaults(allowed_origins=…, allowed_hosts=…)` 工厂 + `check(headers)` 引发 `McpOriginHostRebindingError`。仅 Pydantic 核心,无新的运行时依赖。 |
| [**OpenClaw 执行拒绝列表绕过在 MCP 环回地址生成 (CVE-2026-53820)**](https://nvd.nist.gov/vuln/detail/CVE-2026-53820) | v0.8.31 — 默认拒绝在 MCP 环回地址会话生成处的*已解析有效命令*的重新检查(**CWE-693** 保护机制失败,CVSS 6.9,OWASP-MCP **MCP05**)。OpenClaw < 2026.5.12 允许经过身份验证的调用者通过捆绑的 MCP 环回地址生成路径访问已拒绝的命令,因为**表面**命令检查的执行限制与**实际**执行的命令不同 — 一个名称通过别名 / 包装二进制(`env` , `sudo` , `timeout` , `nice` , …)/ shell 解析为被拒绝的可执行文件。这是在生成边界处的保护机制绕过,**不是**配置时间检查。 **`LoopbackSessionSpawnGuard`** (在 `mcp_spec/loopback_spawn_guard.py` 中)在生成前立即将别名 + 包装二进制文件解包为有效程序并重新检查:拒绝已解析的 shell / 已拒绝的可执行文件,并且不允许在 `allowed_commands` 中解析的程序(默认拒绝)。Shell 是终端(不解包到其 `-c` 脚本),并且完整的解包在 `decision.resolution_chain` 上报告,以便 "有效 ≠ 表面" 绕过是可审计的。`check_spawn(command)` / `enforce(command)`;`openclaw_cve_2026_53820_defaults(allowed_commands=…, aliases=…)` 工厂 + `check(command)` 引发 `LoopbackSessionSpawnError`。仅 Pydantic 核心,无新的运行时依赖。 |
| [**SafeURL IPv6 过渡云元数据 SSRF (CVE-2026-48782)**](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cg7w-rg45-pc59) | v0.8.32 — 将现有的 **`SafeURL`** 元数据阻止列表扩展为规范主机名到打包的 `ipaddress` 形式 **在** 比较之前,关闭 IPv6 过渡 / 替代编码绕过类(**CWE-918**,OWASP **ASI02**)。pydantic-ai 的元数据阻止列表比较主机名 *字符串* ,因此编码 `169.254.169.254` 为 IPv4 映射的 IPv6(`::ffff:169.254.169.254`),IPv4 兼容(`::169.254.169.254`),6to4(`2002:a9fe:a9fe::`),Teredo 或十进制 / 八进制 / 十六进制整数(`2852039166` / `0xa9fea9fe`)绕过它,而 HTTP 客户端仍然可以访问 IMDS — 暴露云 IAM 凭证。**这关闭了上游修复的 [CVE-2026-46678](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cqp8-fcvh-x7r3) 留下的 IPv6 过渡间隙。** 新的 `metadata_ip_candidates(host)` 帮助程序将每个编码(包括每个过渡表单的嵌入式 IPv4)折叠为其打包地址,并与规范元数据 IP 集(AWS/GCP/Azure `169.254.169.254`/`.253`,AWS IPv6 `fd00:ec2::254`,阿里巴巴 `100.100.100.200`)进行比较;合法的公共 IPv6 主机不受影响。**仅附加** — 公共 `SafeURL` 签名不变,检查在 `block_metadata_urls=True` 下默认开启,因此每个 `SafeURLValidator` (和 `SafeURL` Pydantic 类型)都继承它。仅 Pydantic 核心,无新的运行时依赖。 |
| [**SafeURL DNS 重新绑定 SSRF (GHSA-mrvx-jmjw-vggc)**](https://github.com/advisories/GHSA-mrvx-jmjw-vggc) | v0.8.34 — 使 **`SafeURL`** 出口守卫 DNS 重新绑定安全(OWASP-MCP **MCP06** SSRF)。SearXNG MCP 服务器(高,已于 2026-06-19 公开披露)仅验证 *语法* 主机名字符串是否与私有 IP 阻止列表一致 **而没有解析 DNS** — 因此攻击者域名解析为私有 / 环回 IP(像 `nip.io` 这样的通配符 DNS,或自定义记录)通过字符串检查,服务器然后读取任意内部服务。`SafeURLValidator` 获得一个 **`dns_rebinding_guard`** 标志(附加,默认为关闭以保持向后兼容;**在 `dns_rebinding_safe_url_defaults()` OWASP-MCP 预设中开启**):在语法允许列表之后,它 **在调用时解析主机** 并将 **每个** 解析的 A/AAAA 地址与私有 / 环回 / 链路本地 / 元数据阻止列表(`169.254.169.254` , `::1` , `127/8` , `10/8` , `172.16/12` , `192.168/16` , `fc00::/7` )一致;无法解析的主机关闭。`guard.resolve_and_pin(url)` 返回验证的 URL + **固定的 IP** 以连接(解析一次,连接至该 IP),因此在检查和连接之间无法重新绑定记录(TOCTOU)。与 v0.8.32 元数据规范化组合(因此解析的 `::ffff:169.254.169.254` 也被捕获)。仅 Pydantic 核心,无新的运行时依赖。 |
| [**工具输出信任边界守卫 - Agentjacking 类别**](https://labs.cloudsecurityalliance.org/research/csa-research-note-agentjacking-mcp-sentry-injection-20260612/) | v0.8.33 — 在工具缝隙的 **输出** 端面提供按需、每个工具的防御(OWASP-MCP **MCP08** 间接 / 工具结果注入)。所有其他 Airlock 层都保护 *输入* (进入工具的参数);这保护 *输出* — 即将流入代理上下文的工具 / MCP 结果。它标志类似于注入指令的内容(覆盖指令,如 "忽略前面的指令",命令指令,围栏 shell 命令 — **Agentjacking** "解析步骤" 形状 — 以及内嵌在诊断 / 错误字段中的类似工具调用的 JSON),将结果封装在清晰的非受信任数据信封中,以便模型将其视为数据而非指令,并发出结构化事件(通过审计导出器桥接到 OTel)。**默认严格 = 标志 + 信封;从不执行,从不静默丢弃。** 参考案例: **Agentjacking** (Tenet Security,已于 2026-06-12 公开披露;Sentry 缓解措施 2026-06-18 — **一个漏洞类别,无 CVE ID** )和 **[CVE-2026-42824 "SearchLeak"](https://www.varonis.com/blog/searchleak)** (M365 Copilot Enterprise,Varonis,已于 2026-06-15 公开披露)。 **`ToolOutputTrustGuard`** (在 `tool_output_trust_guard.py` 中)`inspect(output)` / `process(output)` / `envelope_output(output)`;通过 `untrusted_tool_output_defaults()` / `UNTRUSTED_TOOL_OUTPUT` 预设常量按需开启每个工具。Pydantic 核心,零依赖。 |
| [**欧盟 AI 法案第 12 条风格的篡改证据决策日志**](./docs/compliance/EU-AI-ACT-ART12.md) | v0.8.40 — **离线** 、 **重启存活** 、 **仅追加** 的哈希链式记录保存,用于工具调用决策层。每个 `validate → policy → execute → sanitize` 决策都追加到 JSON Lines 日志中,其中 `record_hash = SHA-256(canonical(fields incl. prev_hash))` ,因此任何编辑 / 删除 / 重新排序都会破坏后续的每个哈希,并在其确切的序列号处检测到;链在进程重启时重新加载和重新验证(在损坏的链上关闭失败)。 **`agent_airlock.conformance.DecisionLog`** + `export_evidence_bundle()` (离线 JSON + 带有每个 Art. 12 记录保存期望到 airlock 字段的映射的人类可读覆盖表)+ **`airlock-conformance`** CLI(`record` / `verify` / `export`)。无网络,无云;仅存储决策 **元数据** (从不原始参数/结果)。诚实范围:Art. 12 风格的记录保存证据,用于工具调用层 — **不是** 完整的 QMS,也 **不是** 提供商的合格评估(高风险义务在 2026-08-02 适用)。由 `tests/test_conformance_decision_log.py` 固定和篡改证据。Pydantic 核心,零依赖。 |
| [**示例**](./examples/) | 13 个框架集成(11 个适配器发货 + 2 个仅示例)可直接复制粘贴代码 |
| [**安全指南**](./docs/SECURITY.md) | 生产部署检查清单 |
| [**API 参考**](./docs/API.md) | 每个函数、每个参数 |
| [**出口测试**](./docs/security/egress-bench.md) | CVE 固定装置步行器 — 每个先前阻塞的有效载荷都保持阻塞 |
| [**OX MCP 供应链预设**](./docs/presets/ox-mcp-supply-chain-2026-04.md) | 2026-04-20 OX 档案的伞形(10 个 CVE) |
| [**诱导守卫(`mcp_elicitation_guard_2026_04`)](https://github.com/modelcontextprotocol/specification/pull/1487) | v0.6.0 — MCP `tool/elicitation` 往返的运行时缓解措施(规范 PR #1487,草案 2026-04-r1);阻止凭证请求和策略覆盖类别 |
| [**配置路径守卫 (CVE-2026-31402)**](https://nvd.nist.gov/vuln/detail/CVE-2026-31402) | v0.6.0 — Claude Desktop MCP 服务器注册路径遍历缓解措施(CVSS 8.8) |
| [**Gemini 3 代理模式适配器**](https://blog.google/technology/google-deepmind/gemini-3-agent-mode-ga/) | v0.6.0 — `function_call` 载体规范化 + `thought_signature` 隐藏;固定 `SUPPORTED_VERSIONS` 集 |
| [**OAuth `state` 熵守卫**](https://www.blackhat.com/asia-26/briefings/schedule/#oauth-state-injection) | v0.6.0 — base64 / hex / JSON 解码 + 提示注入扫描 OAuth `state` 参数(BlackHat Asia 2026 矢量) |
| [**`airlock console`**](./docs/cli/console.md) | v0.6.0 — 三窗格 Textual TUI,具有实时判决流 + 编辑时重放;由 `airlock[console]` 额外功能控制 |
| [**`airlock attest receipt`**](./docs/attest/receipt.md) | v0.6.0 — Sigstore 兼容的已签名代理运行收据;`emit` 和 `verify` 子命令 |
| [**`policy_bundle.lock`**](./docs/pack/policy-bundle-lock.md) | v0.6.0 — 具有 `Cargo.lock` 语义的哈希固定预设包;`airlock pack lock` 和 `airlock replay --bundle-lock` |
| [**`airlock studio`**](./docs/studio/quickstart.md) | v0.6.0 — 本地标准库 HTTP 排练沙箱;粘贴转录判决 + 运行间差异 |
| [**smolagents 包装器**](https://github.com/huggingface/smolagents/releases/tag/v1.18) | v0.6.0 — `wrap_agent(agent, policy_bundle)` 用于 HuggingFace smolagents 1.18+(第四个一流框架) |
| [**STDIO 元守卫(`mcp_stdio_meta_cve_2026_04`)**](https://www.ox.security/blog/mother-of-all-ai-supply-chains-anthropic-mcp-stdio) | v0.5.9 — 将所有 Airlock STDIO 防御链成一个;2026-04-26 后注册的任何 MCP 服务器的推荐默认值 |
| [**LangGraph 1.0.11 ToolNode 兼容性补丁**](https://github.com/langchain-ai/langgraph/releases/tag/prebuilt%401.0.11) | v0.5.9 — 无声解包在预构建的 1.0.11 列表与字典形状中断中幸存 |
| [**GPT-5.5(“Spud”)代理默认值 + 工具形状适配器**](https://openai.com/index/gpt-5-5/) | v0.5.9 — 将扇出限制在 8 / 上下文限制在 900k / 每次调用出口限制在 512 KB |
| [**能力上限(`agent_capability_default_caps`)**](https://www.anthropic.com/features/project-deal) | v0.5.9 — `SIGN_CONTRACT` / `DELEGATE_TO_AGENT` / `INVOKE_TOOL` / `WRITE_FILE` / `NETWORK_EGRESS` 的程序化上限 |
| [**OWASP Agentic 2026-Q1 覆盖率矩阵**](./docs/owasp-agentic-2026-coverage.md) | v0.5.9 — 10/10 将风险 ID 映射到守卫 + 预设 + 测试,CI 门控在过时条目上失败 |
| [**短形式视频语料库(`wild-2026-04/short_form_video`)**](https://www.blackhat.com/asia-26/briefings/schedule/#tiktok-agent-attacks-zhong) | v0.5.9 — 5 个转录 / 屏幕 / RTL PoCs;`airlock replay --namespace short_form_video` |
| [**`airlock graph serve`**](./docs/graph.md) | v0.5.9 — 具有判决叠加的实时代理 → 工具 → MCP 服务器拓扑结构的本地 Web UI |
| [**`airlock policy compile / explain`**](./docs/policy-as-prompt.md) | v0.5.9 — 具有哈希固定提示和确定性缓存的自然语言策略创作 |
| [**`airlock kill-switch`**](./docs/kill-switch.md) | v0.5.9 — HMAC 签名的集群范围冻结,具有 2-of-3 仲裁重置 |
| [**注释和控制 PR 元数据守卫**](https://oddguan.com/blog/comment-and-control-prompt-injection-credential-theft-claude-code-gemini-cli-github-copilot/) | v0.5.8 — 中和 CVSS 9.4 供应商间 PR 标题提示注入 |
| [**`airlock pack`**](./https://www.anthropic.com/features/project-deal) | v0.5.8 — 签名策略包;`airlock pack install claude-code-ci@2026.04` |
| [**`airlock baseline`**](./https://venturebeat.com/security/rsac-2026-agentic-soc-agent-telemetry-security-gap) | v0.5.8 — 每个代理的 7 天滚动配置文件 + 漂移分数 |
| [**`airlock attest`**](./https://www.anthropic.com/features/project-deal) | v0.5.8 — 每个判决的 DSSE 来源 |
| [**Cloudflare Mesh 兼容性**](https://www.cloudflare.com/press/press-releases/2026/cloudflare-launches-mesh-to-secure-the-ai-agent-lifecycle/) | v0.5.8 — 与 Mesh 并行运行;重复的策略去重 |
| [**仅限清单的 STDIO 模式**](./docs/mcp/manifest-only-mode.md) | v0.5.7 — 签名清单注册表;argv 永远不会源自运行时输入 |
| [**STDIO-taint CI 门控**](docs/security/stdio-taint-scan.md) | v0.5.7 — AST 污染分析器;在 PR 时间标志远程→Popen 流 |
| [**声明式预设 YAML**](./docs/presets/yaml-format.md) | v0.5.7 — 通过仅限标准库的 YAML 解析器进行组合预设 |
| [**CVE-2026-30615 Windsurf 零点击**](docs/cves/cve-2026-30615.md) | v0.5.7 — 需按需差异的 `mcp.json` 自动加载防护;**v0.8.23** 添加 `mcp_config_pin` — 一个生成时 `{name, command, args, env-keys}` 指纹固定集 (`McpConfigPinSet.check()`) ,在注入(未固定的)或突变 STDIO 服务器时关闭失败(提高),在受监视的配置文件未被注入的文件时发出;structlog 和 JSON 行审计通道 |
| [**CVE-2026-6980 GitPilot-MCP**](docs/cves/cve-2026-6980.md) | v0.5.7 — 仓库路径注入(供应商无响应) |
| [**DockerBackend**](docs/sandbox/docker.md) | v0.5.1 强化 + 已知漏洞 |
---
## 关于
由 [**Sattyam Jain**](https://github.com/sattyamjjain) 构建 — 人工智能基础设施工程师。
这最初是一个内部工具,在看到代理在生产数据库中自我幻想之后。现在它属于你。
## 🤝 贡献
我们会在 48 小时内审查每一个拉取请求(PR)。
```bash
git clone https://github.com/sattyamjjain/agent-airlock
cd agent-airlock
pip install -e ".[dev]"
pytest tests/ -v
```
- **发现了 Bug?** [打开一个问题](https://github.com/sattyamjjain/agent-airlock/issues)
- **有功能想法?** [开始讨论](https://github.com/sattyamjjain/agent-airlock/discussions)
- **想贡献代码?** [查看开放的问题](https://github.com/sattyamjjain/agent-airlock/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
---
## 💖 支持
如果 Agent-Airlock 为您节省了生产数据库:
- ⭐ **为此仓库点星** — 帮助其他人发现它
- 🐛 **报告 Bug** — [打开一个问题](https://github.com/sattyamjjain/agent-airlock/issues)
- 📣 **传播消息** — Tweet, blog, share
---
## ⭐ 星历史
<div align="center">
[](https://star-history.com/#sattyamjjain/agent-airlock&Date)
</div>
---
<div align="center">
**由 [Sattyam Jain](https://github.com/sattyamjjain) 使用 🛡️ 构建**
<sub>让 AI 代理更安全,一次一个装饰器。</sub>
[](https://github.com/sattyamjjain)
[](https://twitter.com/sattyamjjain)
</div>
---
<div align="center">
<sub>
**来源:** 本 README 遵循 [awesome-readme](https://github.com/matiassingers/awesome-readme)、[Best-README-Template](https://github.com/othneildrew/Best-README-Template) 和 [GitHub 博客](https://github.blog/open-source/maintainers/marketing-for-maintainers-how-to-promote-your-project-to-both-users-and-contributors/) 的最佳实践。
</sub>
</div>
连接信息
猜你喜欢
暂无推荐服务器