AI Agent 沙箱是 AI Agent 提议的代码、Shell 命令、浏览器会话或工具的可强制执行边界。它限制工作负载能读取、修改、连接、消耗和保留什么。沙箱用于缩小爆炸半径,并不负责判断业务动作是否已授权,也不能证明模型输出正确。
这个边界之所以重要,是因为 Repository 文件、网页、检索文档、Tool Result 和用户输入都可能影响 Agent。应把模型生成动作视为半可信工作负载输入,再根据失败后果选择隔离强度,而不是根据产品名称判断“是否安全”。
核心结论
- 从资产、攻击者、可达接口和不可接受结果开始建模。
- 默认容器主要是打包边界;安全强度取决于共享内核、权限、挂载、设备、网络和 Daemon 访问。
- gVisor、MicroVM 与 WASM 在兼容性、启动、密度和隔离强度上采用不同取舍。
- 尽可能把凭证留在沙箱外,由执行 Broker 中介已批准请求。
- 网络出口默认拒绝,再只开放任务所需的准确目的地与请求形态。
- Snapshot 可以加速启动,也可能保留 Secret、恶意状态或其他租户数据。
- 逃逸、外泄、资源耗尽、生命周期和跨租户失败都需要持续回归。
从威胁模型开始
沙箱边界应包住攻击者可能影响的组件,并把必须可信的资产留在边界外。
先回答:
- Agent 可以运行任意 Native Code、受控命令,还是只能调用固定 Tool API?
- 输入是私有、公开、攻击者可控,还是混合来源?
- 多个客户是否共享同一宿主机?
- 周围有哪些文件、Socket、设备、Cloud Metadata 与网络目标?
- 任务需要哪些凭证或委托权限?
- 工作负载逃逸、耗尽资源或取消后继续存活会造成什么后果?
- 外部副作用能否安全重试?
模型和沙箱处于不可信决策一侧。Agent Runtime控制面、Proxy、Credential Broker、Policy Decision 与外部服务不能因为模型提供了某个 Identity 或 Scope 就直接接受。
按边界比较隔离技术
不存在通用“最佳沙箱”。应选择能兼容工作负载、且剩余风险可接受的最小环境。
| Runtime | 隔离边界 | 优势 | 典型约束 |
|---|---|---|---|
| 加固 Process/Container | Namespace、Cgroup、Capability、Seccomp | 开销低,Linux 兼容性广 | 共享宿主 Kernel,弱配置会暴露宿主资源 |
| gVisor | 在用户态实现大量 Linux System Interface | 减少直接触达宿主 Kernel 的 Syscall 面 | 部分 Syscall 与 I/O 负载存在兼容或性能成本 |
| MicroVM | 硬件虚拟化与独立 Guest Kernel | 更强的租户与 Kernel 边界 | 启动、内存、镜像和编排成本更高 |
| WASM/WASI | 基于 Capability 的 Runtime 接口 | 对兼容 Component 暴露较小能力面 | 不是通用 Linux,生态与接口受限 |
| 独占 VM/Host | 整机边界 | 运维隔离最明确 | 密度最低,Provisioning 成本最高 |
gVisor 官方说明 Sentry 会拦截应用 System Call,并缩小自身可访问的宿主接口;资源耗尽和网络策略仍依赖宿主控制。Firecracker 使用 KVM MicroVM 与精简设备模型。WASI 则让 Component 从无环境权限开始,只获得 Host 明确授予的 Capability。三者解决的问题不同,必须在真实负载上验证兼容性和运营成本。
更强隔离也不是绝对隔离。Hypervisor、用户态 Kernel、Host Kernel、Firmware、设备透传、编排 API 与 Side Channel 都仍有攻击面。
加固文件系统与进程边界
可靠的文件策略从空集合开始:
- 只挂载任务 Workspace;
- 除非任务必须修改,否则输入使用只读挂载;
- 输出写入独立、有容量限制的 Volume;
- 不挂载 Home、SSH Agent、云配置、浏览器 Profile 或包管理凭证;
- Canonicalize 路径并解析符号链接后再判断;
- Root Filesystem 只读,Scratch 空间短期且可销毁;
- 使用非 Root 身份,不增加 Linux Capability;
- 禁止提权、Host Namespace、Raw Device 和 Daemon Socket;
- 限制进程数、CPU、内存、磁盘、文件描述符与墙钟时间。
挂载 /var/run/docker.sock 会把 Docker Daemon 控制权交给工作负载,通常等同宿主机高权限。需要嵌套执行容器时,应通过受控服务或独立隔离 Worker 完成,而不是开启 Privileged Container。
安装 Package 本身也是代码执行。应固定 Registry、Package、Version、Checksum 与构建来源。沙箱能减少恶意依赖的影响,但不会让它生成的制品自动可信。
显式控制网络出口
Network Policy 是沙箱的一部分,不是可选外围设施。Prompt Injection 可以把一条允许的 Shell 命令转化为数据外泄。
更稳妥的路径是:
- 执行环境内不提供直接网络接口;
- 只提供一条通往沙箱外 Proxy 的受控通道;
- 对目的地、Method、Path、Size、Redirect、DNS 与 Content-Type 做精确策略;
- 只有策略通过后才注入凭证;
- 数据返回 Agent 前限制响应大小与类型;
- 记录包含请求和 Policy Identity 的脱敏事件。
Hostname Allowlist 不够。还要考虑 DNS Rebinding、Redirect、其他 IP 表示、IPv6、Loopback、私网地址、云 Metadata Endpoint、Proxy Tunnel,以及“允许的服务本身可以抓取任意 URL”等转发能力。
普通 HTTPS Tunnel 也会限制 Proxy 可见内容。敏感集成应优先在沙箱外提供窄 Tool Adapter,而不是让 Agent 拥有任意 HTTPS 访问。
把 Secret 留在沙箱之外
环境变量、文件、命令参数、Shell History、进程内存和 Crash Dump,都可能被沙箱内取得足够权限的代码读取。更稳妥的 Credential Broker 应:
- 根据可信 Runtime Evidence 认证 Sandbox Workload;
- 接收已批准操作与规范化目标;
- 校验 Tenant、Actor、Resource、Scope 与当前 Policy;
- 签发或注入短期、Audience-bound 凭证;
- 自行发送请求,或返回不可复用 Handle;
- 记录撤销、过期与结果状态。
AI Agent 身份与委托授权负责 Workload Identity 与委托 Token;Agent 工具安全指南负责服务端鉴权。沙箱与二者互补,不能相互替代。
定义机器可检查的沙箱配置
控制面应在工作负载启动前拒绝危险配置。下面的无依赖 Go 示例检查一小部分准入契约;它不是完整容器 Runtime 或安全策略。
package main
import (
"errors"
"fmt"
"strings"
)
type SandboxSpec struct {
RunAsRoot bool
ReadOnlyRoot bool
HostNetwork bool
Mounts []string
EgressHosts []string
MemoryMiB int
PIDs int
WallClockSecond int
}
func (s SandboxSpec) Validate() error {
if s.RunAsRoot || !s.ReadOnlyRoot || s.HostNetwork {
return errors.New("unsafe privilege or host boundary")
}
if s.MemoryMiB <= 0 || s.PIDs <= 0 || s.WallClockSecond <= 0 {
return errors.New("resource limits are required")
}
for _, mount := range s.Mounts {
clean := strings.ToLower(mount)
if strings.Contains(clean, "docker.sock") ||
strings.Contains(clean, "/.ssh") ||
strings.Contains(clean, "/.aws") {
return fmt.Errorf("forbidden mount: %s", mount)
}
}
for _, host := range s.EgressHosts {
if host == "*" || strings.HasPrefix(host, "127.") ||
host == "169.254.169.254" || host == "localhost" {
return fmt.Errorf("forbidden egress target: %s", host)
}
}
return nil
}
func main() {
spec := SandboxSpec{
ReadOnlyRoot: true,
Mounts: []string{"/workspace:ro", "/output:rw"},
EgressHosts: []string{"proxy.example"},
MemoryMiB: 2048,
PIDs: 100,
WallClockSecond: 300,
}
fmt.Println(spec.Validate())
}
预期输出:
<nil>
生产准入还要解析真实路径,校验 Image Digest 与签名,限制 RuntimeClass、Privileged Device 和 Syscall,执行 Network Policy,并把批准的 Profile 与创建出的实例绑定。
管理生命周期、快照与恢复
Agent 沙箱通常在一次 Run 内有状态,Run 结束后应可销毁。每个实例都应具备:
- 不可变的 Run、Tenant、Policy、Image 与 Workspace Identity;
- 创建 Deadline 与最大生存时间;
- 不依赖模型输出的 Lease Renewal;
- 能传递到 Child Process 和 Network Operation 的取消;
- 有界输出收集阶段;
- 销毁与存储删除证据。
Warm Pool 与 Snapshot 可以降低启动延迟,也会引入污染风险。可复用 Base Snapshot 不能包含租户数据、Token、Shell History、模型对话、挂载 Workspace 或运行时生成 Secret。分配前校验 Image/Snapshot Digest。未经可证明 Reset,不能把已分配实例重新放回干净 Pool。
取消不会撤销已经发出的外部 API 调用。业务副作用应留在具备幂等和 Policy 的外部服务中,Dispatch 前写入 Operation Record,结果未知时执行 Reconcile。
可观测,但不制造新的 Secret 副本
有价值的事件包括:
- Sandbox 与 Policy Identity;
- Image 与 Snapshot Digest;
- Process Start、Exit Reason、资源限制与峰值;
- 规范化的文件和 Egress Policy Decision;
- Broker Operation ID 与 Result Class;
- Cancel、Timeout、Cleanup 与 Delete 状态。
不要默认采集完整 Prompt、源码、Shell Output、Token 或环境变量。Hash、计数、分类与有界脱敏片段足够时,不应保留原文。Telemetry 自身也必须执行 Tenant Access Control 与 Retention。
验证边界
发布测试至少主动尝试:
| 攻击或失败 | 预期结果 |
|---|---|
| 读取父目录或跟随 Symlink | 真实路径解析后拒绝 |
| 访问 Metadata、Loopback、私网或 Redirect 目标 | 连接前拒绝 |
| 读取环境或挂载凭证 | 沙箱内不存在可复用 Credential |
| Fork Bomb、Disk Fill、Memory Growth | 硬资源限制与完整终止 |
| 打开 Host Device、Namespace 或 Daemon Socket | 不存在或拒绝 |
| 复用其他租户 Snapshot 或 Output | Identity 不匹配并拒绝分配 |
| Child Process/Network Call 中途取消 | 有界终止并对账副作用 |
| 针对所选 Runtime 的逃逸尝试 | 告警、隔离、修复并进入回归集 |
应度量边界覆盖、拒绝尝试、误拦截、启动 P50/P95、活动与空闲资源、清理延迟、残留数据检查和恢复成功率。对一个 Image 完成一次渗透测试,不能认证未来所有 Runtime 与 Policy。
常见问题
沙箱足以阻止 Prompt Injection 吗?
不足。沙箱只能在 Agent 已经遵循恶意指令后限制可达资源与后果。系统仍需要来源标记、Tool Authorization、输出处理、用户确认和注入攻击评测。
所有 Agent 都不该使用普通容器吗?
不是。低风险、单租户工作可以使用加固容器。当存在恶意 Native Code、共享宿主机、敏感数据或高影响逃逸后果时,才应优先评估更强隔离。
MicroVM 能保证租户隔离吗?
不能保证。它增加 Guest Kernel 与硬件虚拟化边界,但设备暴露、Host Service、Image Provenance、网络、管理 API 和 Hypervisor 漏洞仍然重要。
Agent 多轮执行应该保留沙箱状态吗?
只能有意识地保留。任务状态应存入权威存储,Workspace State 则是有 Scope、版本和过期时间的数据。暂停或 Snapshot 只能覆盖定义好的边界,并证明其他租户不会继承。
最安全的默认网络策略是什么?
不提供直接出口。只把最少的必要操作交给 Broker,由它校验目标与请求形态,在沙箱外注入短期凭证,限制响应,并记录脱敏审计事件。