核心结论

Agent 运行环境的 sandbox 不是单点能力,而是一组分层控制:模型侧权限策略决定“是否允许发起动作”,操作系统或虚拟化边界决定“动作真正能碰到什么”,网络代理和凭据代理决定“能把数据发到哪里、以什么身份发”,审计与审批系统决定“出了问题能否复盘和接管”。对 AI 全栈架构师来说,关键不是问“用了 Docker 没有”,而是把 Agent 的读、写、联网、执行、密钥、资源和审计边界做成一个可验证的运行时控制面。

OpenAI Codex 和 Claude Code 的本地沙箱都体现了同一个方向:默认让 Agent 在工作区内自主执行低风险命令,把联网、越界写入和高风险动作交给审批。区别在于不同系统选择的 OS 原语不同。Codex 文档明确区分 sandbox mode 与 approval policy;Claude Code 的 Bash sandbox 则强调把 shell 命令及其子进程限制在文件和网络边界内。真正进入 SaaS 多租户或不可信代码执行场景时,单纯本机进程沙箱通常不够,需要 gVisor 这类用户态内核或 Firecracker 这类 microVM 承担更强隔离。

威胁模型

Agent sandbox 要防的对象不是传统意义上的“用户上传恶意二进制”一种情况,而是几类叠加风险。

第一类是提示注入后的越权执行。模型可能被仓库里的文档、网页、日志或测试输出诱导,去读取敏感文件、改写代码、提交密钥、安装恶意依赖或访问内网地址。第二类是工具链供应链风险。npm installpip install、测试脚本、构建脚本和 Git hooks 都可能执行任意代码,Agent 一旦自动运行它们,就等于把本地权限交给了项目依赖。第三类是资源耗尽。死循环、fork bomb、海量日志、无限写盘、GPU 占满和长时间网络下载都会拖垮宿主环境。第四类是数据外泄。只限制文件写入没有意义,如果 Agent 能读到密钥并联网,数据仍然可以被发走。

因此 sandbox 的目标要拆成四个问题:它能读哪些路径,能写哪些路径,能连接哪些网络,能消耗多少资源。审批系统再回答第五个问题:什么时候必须停下来等人确认。

本机 Agent 的边界模型

本机 Coding Agent 最常见的边界是“工作区可写、工作区外只读或不可见、网络默认关闭、越界动作需要审批”。这个模型的价值是低摩擦:Agent 可以跑测试、改文件、读代码、生成补丁,但不会默认访问浏览器 cookie、SSH key、云凭据和用户主目录里的其他项目。

一个合理的本机执行链路可以这样设计:

LLM planner
  -> permission policy: classify read / write / network / destructive action
  -> command broker: create sandboxed process
  -> OS sandbox: filesystem, process, syscall and network limits
  -> proxy / credential broker: domain allowlist and short-lived tokens
  -> audit log: prompt, command, cwd, policy version, exit code, diff

这里最容易被忽略的是 command broker。Agent 不应该直接把模型生成的 shell 字符串交给宿主 shell,而是由 broker 统一设置工作目录、环境变量、超时、输出上限、进程组、sandbox profile 和审计字段。所有子进程必须继承同一套限制,否则测试脚本、包管理器或构建工具会成为逃逸路径。

Linux 原语:namespace、cgroup、seccomp 与 LSM

Linux 上的轻量 sandbox 通常由四类内核能力组合而成。

典型技术作用Agent 里的用法
命名空间user、mount、pid、network、ipc、uts namespace隔离用户、文件系统视图、进程树和网络栈让沙箱内看见独立根目录、独立进程树和受控网络
资源控制cgroups v2、rlimit限制 CPU、内存、进程数、I/O 和运行时间防止测试、构建、恶意脚本耗尽宿主资源
系统调用过滤seccomp-BPF缩小能调用的内核接口集合禁止高风险 syscall,降低内核攻击面
强制访问控制Landlock、AppArmor、SELinux以策略限制文件、网络、能力和对象访问给进程再加一层路径和权限规则

seccomp 需要特别谨慎理解。Linux 官方文档明确指出,系统调用过滤本身不是完整 sandbox;它只是减少暴露给进程的内核面。原因很简单:被允许的 syscall 仍然可能触发漏洞,文件和网络的信息流也不是 seccomp 单独能表达清楚的。所以生产级 Agent 不能只说“我用了 seccomp”,还要说明 namespace、cgroup、capability、LSM 和网络策略如何组合。

no_new_privs 也是关键开关。它可以让进程在 execve 后不能通过 setuid、setgid 或文件 capability 获得额外权限,并且常用于让非特权进程安全安装 seccomp filter。对 Agent 来说,任何会执行仓库脚本的沙箱都应默认关闭权限提升路径。

macOS 与 Windows 的本机实现

macOS 通常依赖 Seatbelt/App Sandbox 思路:用系统级 sandbox profile 限制文件、网络和系统服务访问。Codex 文档说明 macOS 本地沙箱使用内置 Seatbelt 框架;Claude Code 文档也说明 macOS 无需额外安装即可使用内置 sandbox。工程上要注意,Seatbelt 对部分 CLI、证书链、网络代理和文件访问语义会有兼容问题,所以需要有明确的 excluded command 策略,但这个例外列表必须很窄。

Windows 的对应能力是 AppContainer、Job Objects、Windows Filtering Platform 和相关访问令牌机制。Microsoft 文档把 AppContainer 描述为应用隔离环境,可以限制文件、注册表、网络、进程和窗口交互。对 Agent 来说,Windows 沙箱要同时关注两件事:文件写入是否被限制在工作目录,网络是否能默认阻断并按域名或能力放行。只靠普通用户权限并不够,因为用户本身往往能读到大量个人文件和开发凭据。

网络隔离:不要只做文件沙箱

Agent sandbox 的数据泄露风险通常发生在“可读加可联网”的组合上。一个只限制写入的沙箱,如果仍能读取 .env、SSH key、云 CLI 配置或浏览器缓存,并且可以自由访问公网,那么它仍然可以外传数据。

推荐的网络模型是默认 deny,再通过代理放行:

sandboxed process
  -> loopback egress blocked by default
  -> metadata IP blocked by default
  -> private CIDR blocked by default
  -> HTTP/SOCKS proxy
  -> domain allowlist, TLS inspection if required, audit log

本地开发场景可以按命令请求临时授权,例如包管理器访问 registry、Git 访问 GitHub、测试访问指定服务。企业或云端场景应把放行粒度从“是否联网”细化到域名、端口、协议、时间窗口和用途。还要显式封锁云 metadata 地址、Kubernetes service account token、内网管理面和本机敏感端口,否则 Agent 很容易从构建任务升级成内部网络探测器。

容器不是完整答案

Docker/containerd 这类容器本质上共享宿主内核,主要依赖 namespace、cgroup、capability、seccomp 和 LSM 做隔离。对可信团队内部任务,这个强度通常够用;对多租户不可信代码,它不是最强边界。Kubernetes 文档也建议,在需要更高隔离时考虑 gVisor 这类 sandbox,而不是只依赖自定义 seccomp profile。

容器方案最常见的错误有四个:把 Docker socket 挂进去,把宿主 home 目录整块挂进去,把云凭据放进环境变量,以及用 privileged container 解决兼容性问题。只要挂了 Docker socket,容器内进程基本就能控制宿主容器运行时;只要开了 privileged,很多 namespace、seccomp、AppArmor/SELinux 约束都会被削弱或绕过。Agent 执行环境里,这些都应该被视为高风险例外,而不是默认配置。

gVisor:用户态内核拦截 syscall

gVisor 的思路是用一个用户态内核 Sentry 来实现大部分 Linux 系统调用,应用看到的是近似 Linux 的 API,但不会直接把大量 syscall 打到宿主内核。每个 sandbox 有独立的 Sentry,文件访问由 Gofer 进程代理。gVisor 官方安全文档强调,它的目标是限制宿主内核暴露面,同时保持大多数容器应用可运行。

这类方案适合需要比普通容器更强隔离、但又希望继续使用 OCI 镜像和 Kubernetes 调度体验的 Agent 平台。代价是兼容性和性能:某些 syscall、内核特性、FUSE、eBPF、特权操作、低层网络或硬件访问可能不可用;系统调用密集型任务会有额外开销。对 Coding Agent 来说,gVisor 很适合跑测试、构建、语言工具链和普通服务,但不适合需要特权容器、内核模块或复杂硬件直通的任务。

Firecracker:用 microVM 做强隔离

Firecracker 是面向 serverless 和多租户场景的轻量 VMM,基于 KVM 启动 microVM。和普通容器相比,每个 microVM 有自己的 guest kernel,隔离边界从“共享宿主内核”提升到“硬件虚拟化边界”。Firecracker 设计文档强调极简设备模型和高密度启动;NSDI 论文还说明 jailer 会在启动 guest 前把 VMM 自身放进 chroot、PID/network namespace、降权和 seccomp-BPF 组合沙箱里。

对 Agent SaaS 来说,Firecracker 的典型生命周期是:

template image
  -> snapshot / rootfs clone
  -> microVM boot
  -> inject workspace and task config
  -> run agent command under cgroup and network policy
  -> stream logs, artifacts and diff
  -> destroy VM or keep warm for short session

这种架构适合运行不可信代码、第三方仓库、用户上传脚本和需要强多租户隔离的自动化任务。代价是平台复杂度更高:要管理镜像、快照、内核、网络、磁盘、启动池、日志采集、VM 回收和漏洞补丁。它不是“更安全的 Docker 命令”,而是一套完整执行平台。

WASI:能力模型最干净,但不是完整 Linux

Wasm/WASI 的安全模型和 POSIX 很不一样。WASI 应用默认没有 ambient authority,不能凭全局用户身份随便打开文件或访问网络,只能使用宿主显式传入的 capability。Wasmtime 文档也强调 WebAssembly 的线性内存、受控分支和导入模型天然提供了较强沙箱基础。

这非常适合插件、策略函数、数据转换、小型工具和可验证扩展。例如让 Agent 调用一个用户上传的数据清洗函数,WASI 比容器更容易表达“只给这个输入文件句柄和这个输出目录句柄”。但 WASI 不适合作为通用 Coding Agent 的唯一执行环境,因为它不能无缝承载完整 Linux shell、包管理器、数据库服务、浏览器测试和大多数原生构建链。

Agent 平台的推荐分层

风险等级推荐边界适用场景关键控制
本机 OS sandbox自己的可信仓库、本地 Coding Agent工作区写入、网络审批、命令超时、审计
rootless container + LSM + egress proxy内部 CI、团队共享 Agent、可控仓库镜像基线、无 Docker socket、资源配额、域名 allowlist
中高gVisor / Kata多租户容器任务、第三方依赖较多的构建用户态内核或轻 VM、Kubernetes 集成、兼容性测试
Firecracker microVMSaaS 执行用户代码、不可信仓库、长期自动化独立 guest kernel、短期凭据、默认离线、销毁式会话
专用Wasm/WASI插件、策略函数、数据转换capability 传参、无 ambient authority、宿主 API 审计

真正落地时可以组合使用。例如本地开发使用 Seatbelt 或 bubblewrap;云端普通任务用 gVisor;高风险用户代码用 Firecracker;用户插件用 WASI。不要试图让一种 sandbox 覆盖所有场景。

凭据与密钥设计

Agent 运行环境最危险的不是模型会犯错,而是它拿到了过宽的身份。正确做法是让 sandbox 内部尽量没有长期密钥,需要访问外部系统时通过 credential broker 申请短期、最小权限、可撤销的凭据。凭据签发应绑定任务 ID、工具名、目标资源、过期时间、审批记录和策略版本。

例如部署工具不应该直接读取个人 SSH key,而应该由 broker 在审批通过后签发一次性部署令牌,且只允许访问目标仓库、目标环境和目标时间窗。数据库工具不应该拿全库管理员密码,而应该拿只读、限表、限行数或只允许调用存储过程的凭据。这样即使 Agent 被提示注入影响,攻击者也只能拿到被策略压缩过的能力。

可观测与审计

Sandbox 不能只在失败时返回一句“权限不足”。生产 Agent 需要保留一条可回放记录:模型请求、上下文摘要、工具列表、命令、cwd、环境变量白名单、sandbox profile、网络请求、资源用量、审批结果、文件 diff、退出码和错误输出。对于被拒绝的动作,也要记录拒绝原因和命中的策略。

建议把审计字段拆成三层:

  1. 策略层:sandbox mode、approval policy、network allowlist、credential scope、policy version。
  2. 执行层:command、argv、cwd、uid/gid、namespace/container/vm id、timeout、resource limit。
  3. 结果层:exit code、stdout/stderr 摘要、文件变更、网络目标、审批人、artifact。

这些记录不仅用于安全复盘,也用于评测 Agent 是否频繁撞权限、是否总在同类任务上超时、是否需要改工具边界。

实施检查清单

  1. 所有 Agent 命令是否经过统一 command broker,而不是直接裸跑 shell。
  2. 工作区外路径是否默认不可写,敏感目录是否默认不可读。
  3. 网络是否默认关闭或走代理,metadata、内网和 localhost 敏感端口是否被阻断。
  4. 是否设置 CPU、内存、进程数、磁盘、输出大小和总运行时间上限。
  5. seccomp、capability、no_new_privs、LSM 是否组合使用,而不是只依赖单一机制。
  6. 包管理器、构建脚本、Git hooks 和测试脚本是否被视为不可信代码执行。
  7. Docker socket、privileged container、宿主 home 目录和长期云凭据是否被明确禁止。
  8. 高风险动作是否需要人工审批,并把审批记录写入同一条 trace。
  9. 云端多租户是否使用 gVisor、Kata 或 microVM,而不是只靠普通容器。
  10. Sandbox 失败、超时、拒绝和资源耗尽是否能被清楚观测和回放。

采用建议

如果是在个人机器上使用 Coding Agent,先采用本机 OS sandbox 加审批策略,重点保护工作区外文件、网络和密钥。如果是在公司内部推广 Agent,优先建立统一 command broker、网络代理和凭据代理,不要让每个团队自己拼 shell 执行器。如果是对外提供 Agent 执行平台,直接按多租户不可信代码设计,优先评估 Firecracker 或 gVisor,并把镜像、快照、网络、审计和回收流程纳入平台工程。

判断一个 Agent sandbox 是否合格,不看宣传里用了多少安全名词,而看它能否稳定回答五个问题:这次任务能读什么,能写什么,能连哪里,能拿什么身份,出了问题能否完整复盘。