跳到主要内容

智能体沙箱与安全代码执行:根据风险匹配隔离深度

· 阅读需 13 分钟
Tian Pan
Software Engineer

大多数发布具备代码执行能力的 LLM 智能体(Agent)的团队都犯了同样的错误:他们将沙箱化视为一种二元属性。要么完全跳过隔离(“我们信任我们的用户”),要么部署 Docker 容器并认为问题已解决。这两种立场在进入生产环境后都经不起考验。

现实情况是,沙箱化存在于一个包含五个不同级别的光谱上,每一级都提供不同的隔离保证、性能配置和运营成本。所选隔离级别与实际风险概况之间的不匹配是大多数智能体安全事件的根本原因 —— 而不是根本没有沙箱。

这篇博文将带你了解沙箱光谱、每个沙箱都必须解决的四个维度的能力限制、从业者经常忽视的逃逸向量,以及根据你的智能体实际行为来匹配沙箱深度的决策框架。

隔离光谱

将智能体沙箱化视为一个刻度盘,而不是一个开关。

级别 0:无沙箱。 直接在宿主操作系统上进行 exec() 或子进程调用。零开销,零隔离。LLM 生成的代码以进程的全权权限运行。这仅适用于开发人员工具,即你在离线环境中执行自己的静态脚本 —— 这类场景几乎没有生产级智能体存在。

级别 1:容器隔离 (Docker/LXC)。 Linux 命名空间(pid、net、mnt、uts、ipc)加上用于资源限制的 cgroups。启动时间以毫秒计,几乎零内存开销。关键弱点是共享内核:主机上的所有容器都运行在同一个 Linux 内核上,这意味着一个未修复的内核 CVE 漏洞会同时危害主机上的每个容器。容器隔离不等于虚拟机隔离。请在单租户、内部环境中的可信代码中使用它。

级别 2:seccomp-BPF + 强化策略。 在进程启动时附加的 seccomp-bpf 过滤器限制了进程可以进行的系统调用。默认的 Docker 配置阻止了大约 44 个系统调用;强化的 AI 智能体配置应该更进一步 —— 阻止 ptracemountunshare、带有 CLONE_NEWUSERclonekeyctlperf_event_openbpf。将其与 --cap-drop=ALL--security-opt no-new-privileges 以及 AppArmor/SELinux 强制访问控制配合使用。开销微乎其微(过滤器评估以纳秒计),但你仍然处于共享内核之上 —— seccomp 减少了攻击面,它并不能消除它。

级别 3:gVisor (用户态内核)。 Google 的开源项目在一个名为 Sentry 的 Go 进程中重新实现了 Linux 系统调用界面。客户机系统调用在到达宿主内核之前被拦截,并在用户态进行处理。为了逃逸,攻击者必须首先突破 Sentry,然后击败保护 Sentry 进程本身的强化 seccomp 配置 —— 这是两个独立的层级。在计算密集型任务上性能开销接近于零,在 I/O 密集型工作负载上为 10–30%。启动时间为毫秒级。启用它只需要更改一个 daemon.json 来使用 runsc 运行时。GPU 支持已在 2024/2025 年添加。gVisor 是在无法使用嵌套虚拟化的 Kubernetes 上运行多租户 SaaS 工作负载的正确选择。

级别 4:微型虚拟机 (Firecracker)。 每个沙箱都有自己专用的 Linux 内核。AWS 使用 KVM 用约 50,000 行 Rust 代码构建了 Firecracker。冷启动时间不到 125 毫秒。每个虚拟机的内存开销低于 5 MiB。与裸机相比,计算开销不到 5%。攻击面的减少是巨大的:Firecracker 仅暴露四个虚拟设备(virtio-block、virtio-net、serial、keyboard),而 QEMU 暴露数百个。Jailer 伴随程序通过降低权限和应用 cgroups 作为第二道防线。通过快照/恢复,沙箱配置时间可通过写时复制(copy-on-write)覆盖层恢复预热的内存镜像,降至约 28 毫秒。这就是 AWS Lambda 运行的方式 —— 每月调用量达数十万亿次 —— 也是 e2b 等托管平台用于 AI 代码执行的方式。对于处理用户提供或 LLM 生成的代码的多租户部署,微型虚拟机是当前的标准。

级别 5:WebAssembly (Wasm/WASI)。 编译为 WebAssembly 的代码运行在基于能力的沙箱中,默认情况下无法访问文件系统、网络或操作系统。每个导入必须由宿主明确授权。亚毫秒级启动,接近裸机的计算性能。局限性:并非所有语言都能干净地编译为 Wasm。Python 需要 Pyodide(编译为 Wasm 的 CPython),它可以工作但冷加载时间较长。Wasm 是插件沙箱、浏览器端代码执行以及在边缘环境中运行的智能体工具的正确选择。它不能取代用于通用代码执行的微型虚拟机隔离,因为 Spectre 类瞬态执行攻击可能会破坏 Wasm 的内存隔离 —— 这是一个在更高安全级别中很重要的已知局限。

能力限制的四个维度

选择隔离级别只是问题的一半。无论你部署什么样的沙箱,都需要明确限制四个能力维度。

文件系统访问。 沙箱应该有一个只读的根文件系统,只允许对指定的工作区目录和 /tmp 进行写操作。至关重要的是,必须阻止对工作区之外配置文件的写访问:~/.gitconfig~/.zshrc~/.local/bin.cursorrules、MCP 配置文件、IDE 配置目录和钩子脚本(hook scripts)。这些是持久化向量 —— 能够写入这些文件的智能体(agent)即使当前会话被销毁,也可以影响未来的沙箱会话。

网络访问。 默认拒绝所有出站流量。如果智能体确实需要外部访问,则允许特定的 API 端点。拦截发往任意解析器的 DNS 查询:基于 DNS 的数据外泄(将敏感数据编码到查询的主机名中)可以完全绕过基于 IP/端口的出站过滤器,而防御者对此利用不足。智能体与沙箱之间的内部通信应使用 vsock(内核到内核)而非 TCP,以避免暴露网络接口。

系统调用(Syscall)面。 除了 seccomp 默认设置外,每个沙箱都应明确禁用能够实现提权的系统调用:ptrace(进程检查)、mount(文件系统操作)、带有新用户命名空间的 unsharekeyctlbpf。使用 --cap-drop=ALL 丢弃所有 Linux 能力,并仅根据特定工作负载的需要重新添加。

进程生成。 使用 cgroups 的 pids.max 限制沙箱可以创建的进程数量。这可以限制 fork 炸弹攻击和资源耗尽。更重要的是,要谨慎使用任何等效于 --allow-run 的设置:允许沙箱生成任意子进程在很大程度上会让能力限制失效,因为子进程会继承操作系统层级的访问权限,而不受父进程权限标志的影响。

从业者容易忽视的逃逸向量

沙箱频谱解决了容器化问题。从业者经常会忽视另一类逃逸向量,无论沙箱级别如何,这些向量都会存在。

Docker 套接字(socket)挂载。 在容器内部挂载 /var/run/docker.sock 会授予完整的 Docker API 访问权限,这等同于宿主机的 root 权限。这种情况在从开发环境迁移到生产环境的配置中非常常见。需要对此进行明确审计。

路径前缀过滤中的符号链接(Symlink)遍历。 2025 年的多个高危 CVE 表明,简单的路径前缀检查(如 if path.startswith("/workspace"))可以通过符号链接绕过。在一个广泛部署的 MCP 实现中,文件系统服务器就存在这个漏洞:通过创建从 /workspace/escape/etc/passwd 的符号链接,将工作区内的读取调用转变为对宿主机任意文件的读取。在进行任何前缀检查之前,请使用真实路径解析(os.path.realpath())。

配置文件投毒。 通过提示注入(prompt injection)指示智能体写入 ~/.gitconfig 或 IDE 钩子脚本,会导致用户下次打开编辑器时执行任意代码 —— 而这发生在任何沙箱之外。这是一种供应链攻击,沙箱无法防止这种攻击,因为它利用了沙箱文件系统边界与用户主目录之间的间隙。缓解措施是对工作区之外的所有路径使用只读文件系统挂载,而不仅仅是阻止对特定文件名的写入。

--allow-run 逃逸。 在 Deno 的权限模型和类似系统中,允许子进程执行会使能力限制失效。子进程继承操作系统级别的访问权限。如果你的智能体工具调用模式需要执行(exec)任意二进制文件,那么无论外层沙箱如何,你都回到了级别 0。

容器部署中的内核 CVE 传播。 CVE-2024-1086(一个 netfilter 释放后使用漏洞)在 2025 年 10 月前一直被勒索软件活动积极利用。由于共享内核,未打补丁的宿主机上的所有容器都会同时面临风险。如果你在共享宿主机上的容器中运行多租户智能体工作负载,那么单个未修复的内核 CVE 漏洞产生的爆炸半径将影响所有租户。请保持内核版本最新,并针对内核 CVE 是重要威胁模型的工作负载考虑使用 gVisor 或轻量级虚拟机(microVMs)。

通过对话绕过沙箱的提示注入。 华盛顿大学的研究发现,63.4% 没有适当隔离的 LLM 智能体通过对话泄露了敏感数据 —— 而不是通过代码执行。如果注入的指令要求它这样做,一个“乐于助人”的智能体将总结它读过的文件,而不管代码执行沙箱允许什么。技术沙箱无法解决语义层的问题。缓解措施是在架构上:在隔离的上下文中运行接触敏感数据的智能体工具,而不与外部输入源共享该上下文。

将沙箱深度与风险特征相匹配

三个问题决定了合适的隔离级别:

代码是否是由 LLM 输出在运行时生成的? 如果是,那么单纯的容器对于任何多租户部署都是不够的。LLM 生成的代码具有不可预测的系统调用和文件系统访问模式,无法提前进行特征化。至少使用 gVisor;对于生产环境的多租户工作负载,使用 Firecracker。

多个租户是否共享基础设施? 如果是,租户隔离需要专门的内核边界。使用 Firecracker microVM 或 Kata Containers(它在标准 Kubernetes API 之后封装了 microVM)。200 毫秒的 Kata 容器启动开销是获得虚拟机级隔离且无需更改现有 Kubernetes 工作流程的代价。

工作负载是否需要 GPU 访问? 如果是,目前 Firecracker 并不适用 —— 它不支持 PCIe/GPU 透传。使用 gVisor(通过与 Groq 的合作,在 2024/2025 年增加了 GPU 支持)或全功能虚拟机。对于智能体需要 GPU 加速推理的 AI 工作负载来说,这是一个重大的架构约束。

得出的决策矩阵:

场景推荐方法
内部工具、信任的开发者、单租户Docker + 硬化的 seccomp 配置
LLM 代码、单租户 SaaSgVisor (runsc 运行时) 或 Docker + --security-opt no-new-privileges
多租户 LLM 代码执行Firecracker microVM 或 Kata Containers
金融 / 医疗 / PII 工作负载Firecracker + 网络出站白名单 + 机密注入 (绝不使用环境变量)
来自第三方的插件/扩展系统WebAssembly (WASI) 或 Firecracker
浏览器端智能体工具WebAssembly (继承浏览器沙箱)

性能开销的权衡比你想象的要小

针对 MicroVM 的性能质疑在 2026 年看来比以往任何时候都要苍白。Firecracker 的冷启动时间低于 125 ms,且每个虚拟机(VM)的内存开销不到 5 MiB。通过快照/恢复(snapshot/restore)机制,利用预热快照上的写时复制(copy-on-write)内存叠加层,端到端的沙箱配置时间可缩短至 28 ms——这比许多数据库查询的往返时间还要快。AWS Lambda 每月处理数十万亿次的调用正是基于此。虚拟机内部的计算开销不到裸机的 5%。

gVisor 的开销特征则有所不同:在计算密集型任务中几乎为零,但在 I/O 密集型工作负载中为 10–30%。对于主要进行文本处理和 API 调用的 Agent 来说,gVisor 的开销微不足道;但对于涉及大量文件 I/O 的 Agent,这种开销则是可感知的。

MicroVM 隔离的真实成本在于运维:即构建或采用编排层,以在大规模环境下管理虚拟机的生命周期。像 e2b 这样的托管平台提供了开箱即用的、低于 200 ms 的配置能力。Kata Containers 则使其能够通过标准的 kubectlcontainerd 进行调用,而无需构建自定义的 VMM 编排层。对于大多数团队来说,真正的选择是在这些现有方案之上进行构建,而不是在抽象层面上纠结于选择 Docker 还是 Firecracker。

从威胁模型开始,而非技术

Agent 沙箱化最难的部分不在于实现——而是在于抵制那种脱离威胁模型而盲从(cargo-cult)某种技术选择的诱惑。Docker 容器并非“不安全”:它们是处理单租户受信任代码工作负载的正确工具。Firecracker MicroVM 也并非大材小用:当涉及多租户、LLM 生成的代码执行时,它们就是正确的工具。

那些“翻车”的从业者通常是因为:

  • 将适用于单租户的隔离级别错误地应用于多租户部署
  • 在运行 Agent 代码的容器中挂载了 Docker socket
  • 实施了文件系统限制,却对 DNS 出站(egress)不加限制
  • 限制了代码执行,却让对话上下文处于注入指令的可触及范围内

沙箱图谱为你提供了技术词汇,而威胁模型则为你指明了适可而止的边界。两者缺一不可。

References:Let's stay in touch and Follow me for more thoughts and updates