跳转到内容

安全沙箱设计

安全沙箱设计

学习目标

读完本章后,你将能够:

  • 理解 AI Agent 安全沙箱的多层防御架构
  • 掌握 Linux(bwrap/seccomp/landlock)和 macOS(Seatbelt)沙箱技术
  • 设计命令级别的安全策略引擎
  • 评估不同沙箱方案的适用场景和权衡

前置知识

  • Linux 命名空间(namespace)基础
  • 系统调用(syscall)基本概念
  • 进程权限模型(UID/GID、capabilities)

核心概念

1. 为什么 Agent 需要沙箱

AI Agent 具有执行任意代码的能力,这既是其价值所在,也是最大的安全风险:

  • 数据泄露:Agent 可能将敏感代码上传到外部服务
  • 系统破坏:Agent 可能误删文件、修改系统配置
  • 恶意利用:被诱导执行恶意命令(如删除数据库、加密勒索)
  • 供应链攻击:Agent 下载并执行不可信依赖

沙箱的目标是:即使 Agent 被攻击或出错,其造成的损害也被限制在可控范围内。

2. 多层防御架构

生产级 Agent 沙箱采用**纵深防御(Defense in Depth)**策略:

每层都是独立的防线,即使一层被突破,其他层仍然提供保护。

3. Linux 沙箱技术栈

Bubblewrap(bwrap)— 文件系统隔离

bwrap 是一个轻量级的容器化工具,无需 root 权限即可创建隔离的文件系统视图:

Terminal window
bwrap \
--ro-bind / / \ # 根目录只读挂载
--bind /home/user/proj /home/user/proj \ # 特定目录可写
--tmpfs /tmp \ # 独立的 /tmp
--unshare-net \ # 隔离网络命名空间
-- /bin/bash

关键特性

  • 用户命名空间(user namespace):普通用户可运行
  • 文件系统视图完全可控:只读、可写、不可见
  • 设备树最小化:--dev /dev 只提供基本设备

seccomp — 系统调用过滤

seccomp(secure computing mode)是 Linux 内核的安全机制,可以限制进程可调用的系统调用:

白名单模式:只允许显式列出的 syscall
黑名单模式:只允许未显式禁止的 syscall

网络相关的 seccomp 策略

  • Restricted 模式:阻断 connect/accept/bind/listen 等,仅允许 AF_UNIX socket
  • ProxyRouted 模式:仅允许 AF_INET/AF_INET6,强制流量走代理桥

危险 syscall 过滤

  • ptrace:进程调试,可被用于提权
  • process_vm_readv/writev:跨进程内存读写
  • io_uring_*:新型异步 I/O,攻击面大

no_new_privs

PR_SET_NO_NEW_PRIVS 是一个进程标志,禁止该进程及其子进程通过 execve 获取更高权限(如 SUID 程序):

prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);

这是防止沙箱内执行提权程序的关键防线。

4. macOS Seatbelt

macOS 使用 sandbox-exec 工具和 SBPL(Sandbox Profile Language)定义沙箱策略:

sandbox-exec -p "(version 1)
(allow default)
(deny network*)
(allow file-read* (subpath \"/home/user\"))" -- /bin/bash

特点

  • 基于 Mach 内核的强制访问控制(MAC)框架
  • 策略文件编译为二进制格式,内核直接执行
  • 支持细粒度的文件系统、网络、进程权限控制

5. 命令策略引擎

除了系统级沙箱,Agent 还需要命令级别的策略控制

策略模型

  • PrefixRule:基于命令前缀的匹配规则(如 ["git", "status"]
  • NetworkRule:基于目标主机和协议的规则
  • DecisionAllow / Prompt / Forbidden

策略语言:使用 DSL(如 Starlark)表达策略,支持:

  • 前缀匹配:prefix_rule(pattern=["git", "status"], decision="allow")
  • 网络规则:network_rule(host="api.github.com", protocol="https", decision="allow")
  • 运行时追加:用户批准后动态添加规则

设计模式详解

权限提升控制

沙箱内启动的交互式 shell 可能执行外部命令,需要控制其权限边界:

三种决策

  • Run:在沙箱内直接执行(透明 execv)
  • Escalate:提升到服务器侧执行,可指定沙箱级别
  • Deny:拒绝执行

实现机制

  • 通过 EXEC_WRAPPER 环境变量注入 execve wrapper
  • Wrapper 通过 Unix Domain Socket 向 EscalationServer 发送请求
  • 每个请求使用独立的 stream socket,避免并发冲突

代理网络路由

当沙箱隔离网络命名空间时,需要为合法的网络请求提供出口:

实现

  • 在主机侧创建 Unix Domain Socket 桥接器
  • 在 bwrap 隔离的网络命名空间内,将代理环境变量指向本地 UDS
  • 代理桥将所有流量转发到配置的 HTTP/SOCKS5 代理

这实现了网络隔离 + 强制代理的组合:进程无法直接访问外部网络,所有流量必须经过审计过的代理。


问题与规避

bwrap 在容器环境中的兼容

问题:在 Docker 容器内运行 bwrap 时,--proc /proc 等选项可能被拒绝。

对策

  • 检测容器环境,自动降级沙箱策略
  • 回退到纯 seccomp 过滤(不隔离文件系统)
  • 提供 --dangerously-bypass-sandbox 应急选项

seccomp 的误伤

问题:过于严格的 seccomp 规则可能阻断合法的系统调用(如某些动态链接库的初始化)。

对策

  • 基于实际使用场景测试 seccomp 规则
  • 提供 --seccomp-log 模式:只记录不阻断,用于调试
  • 允许用户通过配置文件添加自定义允许列表

策略文件的并发修改

问题:多个 Agent 实例同时修改策略文件,可能导致数据损坏。

对策

  • 使用文件锁(flock)保护策略文件的读写
  • 原子写入:先写入临时文件,再重命名替换
  • 策略文件使用追加模式,减少写冲突

设计取舍

强隔离(内核沙箱)vs 轻量控制(策略引擎)

维度内核沙箱(bwrap/seccomp)策略引擎(DSL)
隔离强度强(内核强制执行)弱(应用层检查)
性能开销中(命名空间切换)低(纯软件检查)
灵活性低(需要 root/特定权限)高(动态规则)
用户体验透明(用户无感知)显式(提示审批)

推荐策略:内核沙箱作为底线保障,策略引擎作为精细化控制。两者结合实现纵深防御。

自动化审批 vs 人工确认

方案优势代价
全自动流畅、无中断安全风险、难以审计
全人工绝对安全、可审计体验极差、效率低
规则驱动平衡安全与流畅策略配置复杂
学习模式自动适应用户习惯冷启动问题、错误学习

推荐策略:初始阶段采用全人工确认,随着规则积累逐步过渡到规则驱动。

浏览器环境中的域名级沙箱

在浏览器自动化场景中,Agent 会访问不可信的第三方网页。此时沙箱的边界不是进程,而是域名

域名白名单/黑名单机制

browser = BrowserSession(
allowed_domains=["*.google.com", "github.com"],
prohibited_domains=["malicious-site.com"],
)

域级凭据注入

agent = Agent(
sensitive_data={
"github.com": {"username": "user", "password": "pass"},
"*.google.com": {"email": "user@gmail.com"},
},
)

凭据仅在与 allowed_domains 匹配的域上自动注入。当检测到 sensitive_data 但未设置 allowed_domains 时,系统应发出安全警告——因为 Agent 访问恶意网站时可能遭遇 prompt-injection 攻击,导致凭据被窃取。

域模式匹配

  • 精确匹配:"github.com" 匹配 github.com
  • 通配符匹配:"*.google.com" 匹配 mail.google.comdocs.google.com
  • 协议无关:匹配时忽略 http:// / https:// 前缀

弹窗自动关闭作为 Prompt-Injection 防御

网页可以通过 JavaScript alert()confirm()prompt() 弹出对话框。在浏览器自动化场景中,这些弹窗可能被恶意网页用于:

  • 模拟系统登录界面:诱导 Agent 输入凭据
  • 显示伪造的”操作成功”消息:欺骗 Agent 认为任务已完成
  • prompt() 窃取信息:弹出的输入框可能诱导 Agent 输出敏感数据

防御策略PopupsWatchdog 监听 JavaScript 对话框事件,自动关闭并记录消息内容。被自动关闭的弹窗消息会注入到 Agent 的上下文中(如 Auto-closed JavaScript dialog: "Enter your API key"),让 Agent 知道发生了什么。

设计权衡

  • 优点:防止所有基于弹窗的 prompt-injection 攻击
  • 代价:合法的确认弹窗也会被自动关闭(如”确定要删除吗?”)
  • 替代方案:将弹窗转发给 Agent 决策(增加复杂度但更灵活)

参考来源


补充:Cline 的审批模式与安全控制

来源:Cline(cline/cline)apps/vscode/src/core/task/tools/autoApprove.tsapps/vscode/src/core/permissions/CommandPermissionController.ts,commit 791d238

三级自动审批策略

Cline 在应用层实现了三级自动审批,与内核沙箱形成互补:

各级别配置

级别配置项安全等级
Yolo Modemode: "yolo"最低,所有工具无确认执行
Auto-approve Allmode: "autoApproval"中等,浏览器/MCP 工具仍需确认
细粒度per-tool alwaysAllow + 路径限制最高,每个工具可独立配置

设计启示:审批策略应该是一个安全滑块,而非二元选择。从 Yolo(最快)到细粒度(最安全),用户可以根据当前项目敏感度动态调整。

.clineignore 文件访问控制

Cline 实现了一个类似 .gitignore.clineignore 机制,限制代理访问特定文件和目录:

  • 在所有文件列表、搜索、读取操作中自动过滤匹配的文件
  • 支持 glob 模式(node_modules/***.env.git/**
  • 即使工具被批准执行,也无法访问被 .clineignore 屏蔽的文件

为什么需要两层文件控制? 审批控制的是”是否允许操作”,.clineignore 控制的是”操作范围”。即使 Agent 被批准写入文件,它也不应该访问 .git/node_modules/

潜在陷阱.clineignore 只在应用层过滤,不能替代文件系统级权限。如果 Agent 通过 execute_command 调用外部工具(如 find),可能绕过 .clineignore 的过滤。因此需要与 CommandPermissionController 联合使用。

链式命令分段验证

CommandPermissionController 对复杂命令的安全处理策略:

# 伪代码:链式命令验证
function validateCommand(cmd: string): Decision {
// 1. 按 && ; | 分段
const segments = splitByOperators(cmd)
// 2. 每段独立验证
for (const seg of segments) {
if (!matchesAllowedPattern(seg)) {
return Decision.Prompt // 需要用户确认
}
}
// 3. 子 shell 递归验证
const subshell = extractSubshell(cmd) // $(...) or `...`
if (subshell) {
return validateCommand(subshell) // 递归验证
}
return Decision.Allow
}

重定向操作符检测>>>< 等重定向可能用于覆盖敏感文件(如 ~/.ssh/authorized_keys)。Cline 对包含重定向的命令额外检查目标路径,如果被保护则拒绝执行。

设计取舍:完全禁止复杂命令会严重影响开发体验(如 ls | grep foo | head -5),但不验证又容易受到命令注入攻击。Cline 选择分段验证 + 子 shell 递归的中间方案:允许复杂命令,但每段都必须通过模式匹配。

GateGuard 事实强制模式

GateGuard 是一种在首次编辑/写入前强制 Agent 了解上下文的安全门控模式。

工作原理

核心规则:每个文件的首次编辑/写入操作被阻止,除非 Agent 能证明自己已经阅读并理解了该文件的上下文。后续编辑不再触发 Gate。

防御目标

攻击向量GateGuard 防御
Agent 盲目修改不了解的文件强制先 Read 再 Edit
破坏隐含约束(如 schema 兼容性)强制检查导入者和数据消费者
绕过用户指令直接操作强制对照用户指令执行

与审批模式的关系

GateGuard 不是传统的”是否允许操作”审批,而是操作顺序的强制约束

维度传统审批GateGuard
控制点”能不能做""做之前有没有先了解”
触发条件敏感工具调用每个文件的首次编辑
解除条件用户确认Agent 证明已阅读上下文
后续操作每次都需要审批首次通过后不再触发

设计优势

  • 减少破坏性编辑:强制 Agent 在修改前先了解文件的完整上下文
  • 防止”走捷径”:阻止 Agent 通过弱化 lint 配置来绕过错误(配合 Config Protection 钩子)
  • 对每个文件只触发一次:不会在每个编辑轮次都增加延迟

陷阱

  • 首次编辑延迟增加:Agent 需要额外一轮 Read 操作来了解上下文
  • 对小型文件的过度防御:对于一目了然的小文件,GateGuard 可能增加不必要的步骤
  • 缓解方案:GateGuard 可以通过 ECC_GATEGUARD=off 临时关闭

补充:Hermes Agent 的信任模型分层

来源:Hermes Agent(NousResearch/hermes-agent)SECURITY.mdtools/approval.py,commit 2517917

唯一安全边界:OS 级隔离

Hermes 的安全策略有一个核心原则:进程内没有任何组件构成对对抗性 LLM 的 containment。审批门、输出脱敏、模式扫描器、工具白名单都是启发式组件,不是安全边界。

两层 OS 级隔离

隔离类型范围适用场景
终端后端隔离仅覆盖 shell/文件操作可信 LLM + 防止误操作
全进程包装整个 Agent 进程树不可信输入源 + 生产部署

全进程包装支持 Docker Compose 和 NVIDIA OpenShell,后者提供声明式策略(文件系统、网络 L7 出口、进程/syscall、推理路由)。

审批门作为事故预防

Hermes 的审批门(tools/approval.py)有五层检测:

  1. Hardline:无条件阻止(rm -rf /mkfs、fork bomb 等),yolo 模式下也不允许
  2. Sudo stdin guard:阻止密码猜测攻击
  3. DANGEROUS_PATTERNS:约 47 个模式匹配(递归删除、chmod 777、SQL DROP 等)
  4. Smart Approval:使用辅助 LLM 评估风险
  5. Tirith:外部安全扫描

关键设计:审批门定位是合作模式下的错误捕捉,不是对抗性防护。Shell 是图灵完备的,字符串黑名单在结构上是不完整的。

凭证作用域

Hermes 默认从传递给子进程的环境中剥离凭证(API key、网关 token):

  • Shell 子进程、MCP 子进程、代码执行子进程默认不继承凭证
  • 技能/插件运行在 Agent 进程内,可以读取 Agent 能读到的所有内容
  • 缓解措施:安装前审查,不是运行时脱敏

案例补充:CodeWhale 多平台沙箱与审批策略引擎

本补充基于 CodeWhale 源码分析,首次覆盖于 2026-06-01。

CodeWhale 展示了沙箱与审批策略分离设计的实践:

三层操作模式

模式写入权限审批门沙箱
Plan只读不适用只读策略
Agent可写入每个破坏性操作需确认平台沙箱(如有)
YOLO可写入自动批准所有工具平台沙箱(如有)

多平台沙箱实现

  • macOS:Seatbelt(sandbox-exec)——活跃的强制访问控制策略
  • Linux:Landlock(内核 5.13+)文件系统访问控制 + seccomp + bwrap(Bubblewrap)检测,但尚未正式执行
  • Windows:计划通过 Job Object 进程树限制,目前不声称文件系统/网络/注册表隔离
  • 进程加固(Linux v0.8.46+):PR_SET_DUMPABLE=0NO_NEW_PRIVSRLIMIT_CORE=0

审批引擎关键设计

  1. 审批与沙箱分离execpolicy 负责审批决策,sandbox 负责资源限制——两个正交的防御层
  2. 审批缓存:用户勾选”remember”后,同类操作后续自动批准,立即翻转当前 turn 的审批标志
  3. MCP 工具同流:MCP 发现的工具走同样的审批框架——只读 MCP 助手在 suggestive 模式下可跳过审批
  4. 五层审批检测(Hermes 模式参考):Hardline 无条件阻止 → Sudo 防御 → 模式匹配 → 辅助 LLM 评估 → 外部扫描

设计权衡

  • 审批门定位为”合作模式下的错误捕捉”,不是对抗性防护——Shell 是图灵完备的,字符串黑名单结构上不完备
  • macOS Seatbelt 是唯一活跃的完整沙箱;Linux/Windows 沙箱在 helper 执行前不视为完整 OS 级隔离