AI Agent 沙箱是 AI Agent 提议的代码、Shell 命令、浏览器会话或工具的可强制执行边界。它限制工作负载能读取、修改、连接、消耗和保留什么。沙箱用于缩小爆炸半径,并不负责判断业务动作是否已授权,也不能证明模型输出正确。

这个边界之所以重要,是因为 Repository 文件、网页、检索文档、Tool Result 和用户输入都可能影响 Agent。应把模型生成动作视为半可信工作负载输入,再根据失败后果选择隔离强度,而不是根据产品名称判断“是否安全”。

核心结论

  • 从资产、攻击者、可达接口和不可接受结果开始建模。
  • 默认容器主要是打包边界;安全强度取决于共享内核、权限、挂载、设备、网络和 Daemon 访问。
  • gVisor、MicroVM 与 WASM 在兼容性、启动、密度和隔离强度上采用不同取舍。
  • 尽可能把凭证留在沙箱外,由执行 Broker 中介已批准请求。
  • 网络出口默认拒绝,再只开放任务所需的准确目的地与请求形态。
  • Snapshot 可以加速启动,也可能保留 Secret、恶意状态或其他租户数据。
  • 逃逸、外泄、资源耗尽、生命周期和跨租户失败都需要持续回归。

从威胁模型开始

沙箱边界应包住攻击者可能影响的组件,并把必须可信的资产留在边界外。

先回答:

  1. Agent 可以运行任意 Native Code、受控命令,还是只能调用固定 Tool API?
  2. 输入是私有、公开、攻击者可控,还是混合来源?
  3. 多个客户是否共享同一宿主机?
  4. 周围有哪些文件、Socket、设备、Cloud Metadata 与网络目标?
  5. 任务需要哪些凭证或委托权限?
  6. 工作负载逃逸、耗尽资源或取消后继续存活会造成什么后果?
  7. 外部副作用能否安全重试?
flowchart LR A["不可信 Prompt、文件与 Tool Result"] --> B["Agent Runtime"] B --> C["沙箱执行环境"] C --> D["只读 Workspace 与临时卷"] C --> E["Egress Proxy"] E --> F["凭证 Broker 与 Policy"] F --> G["已批准外部服务"] C --> H["资源与生命周期控制器"] C --> I["脱敏事件流"]

模型和沙箱处于不可信决策一侧。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 命令转化为数据外泄。

更稳妥的路径是:

  1. 执行环境内不提供直接网络接口;
  2. 只提供一条通往沙箱外 Proxy 的受控通道;
  3. 对目的地、Method、Path、Size、Redirect、DNS 与 Content-Type 做精确策略;
  4. 只有策略通过后才注入凭证;
  5. 数据返回 Agent 前限制响应大小与类型;
  6. 记录包含请求和 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 或安全策略。

go
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())
}

预期输出:

text
<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,由它校验目标与请求形态,在沙箱外注入短期凭证,限制响应,并记录脱敏审计事件。

参考资料