微信扫码
添加专属顾问
揭秘OpenClaw沙箱系统的企业级安全架构,看阿里如何打造AI智能体安全防线。 核心内容: 1. OpenClaw沙箱系统的核心安全机制与隔离策略 2. 多层级容器管理与工具权限控制体系 3. 实战配置示例与安全最佳实践
三、各系统模块讲解
3.8 SandBox 沙箱系统
Sandbox 是 OpenClaw 的 Docker 隔离层,用于在容器中执行 AI Agent 的工具操作,而非直接在主机上运行。
src/agents/sandbox/├── types.ts # 核心类型定义├── config.ts # 配置合并逻辑├── context.ts # 入口点 - 解析沙箱上下文├── docker.ts # Docker 容器管理├── browser.ts # 隔离浏览器容器├── tool-policy.ts # 工具允许/拒绝策略├── validate-sandbox-security.ts # 安全验证├── fs-bridge.ts # 文件系统操作桥接└── prune.ts # 容器自动清理
禁止的绑定挂载:
禁止的网络模式:
默认安全配置:
隔离时工具过滤顺序:
默认允许的工具:exec、read、write、edit、apply_patch、image 等
默认禁止的工具:browser、canvas、nodes、cron、gateway 及所有消息通道
{ "agents": { "defaults": { "sandbox": { "mode": "non-main", "scope": "session", "workspaceAccess": "none", "docker": { "image": "openclaw-sandbox:bookworm-slim", "network": "none", "memory": "512m", "cpus": 1 }, "prune": { "idleHours": 24, "maxAgeDays": 7 } } } }}3.9 记忆管理
OpenClaw 的记忆系统采用 "文件即真相" 的设计哲学:
~/.openclaw/workspace/├── MEMORY.md # 长期记忆(精选、持久化)└── memory/ └── YYYY-MM-DD.md # 每日记忆日志(append-only)
分层设计:
type MemorySource = "memory" | "sessions";type MemorySearchResult = { path: string; // 文件路径 startLine: number; // 起始行号 endLine: number; // 结束行号 score: number; // 相关性得分 snippet: string; // 文本片段(~700 字符) source: MemorySource; // 来源类型 citation?: string; // 引用标注};记忆索引管理器 (MemoryIndexManager)
核心职责:
关键特性:
记忆搜索工具
memory_search - 语义搜索
memory_get - 定向读取
搜索流程
用户查询 ↓关键词提取 (FTS)向量嵌入 ↓并行搜索 ├─ 向量搜索(语义相似) └─ BM25 搜索(关键词匹配) ↓加权融合 ↓后处理 ├─ 时间衰减 └─ MMR 去重 ↓Top-K 结果
为什么需要混合搜索?
向量搜索优势:
向量搜索劣势:
BM25 优势:
分数融合算法
finalScore = vectorWeight * vectorScore + textWeight * textScore
权重归一化为 1.0,默认 vectorWeight=0.7,textWeight=0.3
MMR(最大边际相关性)去重
目的:避免返回重复或高度相似的片段
算法:
score = λ × relevance - (1-λ) × max_similarity_to_selected
λ 参数:
查询:"家庭网络设置"无 MMR:1. memory/2026-02-10.md (0.92) ← 路由器 + VLAN2. memory/2026-02-08.md (0.89) ← 路由器 + VLAN(重复!)3. memory/network.md (0.85)有 MMR (λ=0.7):1. memory/2026-02-10.md (0.92) ← 路由器 + VLAN2. memory/network.md (0.85) ← 参考文档(多样)3. memory/2026-02-05.md (0.78) ← AdGuard DNS(多样)
时间衰减
目的:让近期记忆排名更高
公式:
decayedScore = score × e^(-λ × ageInDays)
半衰期:默认 30 天
常青文件(不衰减):
支持的提供商
自动选择逻辑
if (local.modelPath 存在) return "local";if (OpenAI key 可用) return "openai";if (Gemini key 可用) return "gemini";if (Voyage key 可用) return "voyage";if (Mistral key 可用) return "mistral";return disabled;
批量索引
SQLite 数据库结构
-- 文件表CREATE TABLE files ( path TEXT PRIMARY KEY, source TEXT, mtime INTEGER, hash TEXT);-- 分块表CREATE TABLE chunks ( id TEXT PRIMARY KEY, path TEXT, startLine INTEGER, endLine INTEGER, text TEXT, embedding BLOB, source TEXT);-- 向量表CREATE VIRTUAL TABLE chunks_vec USING vec0(...);-- 全文索引CREATE VIRTUAL TABLE chunks_fts USING fts5(...);-- Embedding 缓存CREATE TABLE embedding_cache ( hash TEXT PRIMARY KEY, embedding BLOB);
索引更新策略
触发条件:
会话索引:
预压缩提示
触发时机:会话接近自动压缩时
机制:
tokenEstimate > contextWindow - reserveTokensFloor - softThresholdTokens
行为:
配置示例
{ agents: { defaults: { compaction: { reserveTokensFloor: 20000, memoryFlush: { enabled: true, softThresholdTokens: 4000, systemPrompt: "Session nearing compaction...", prompt: "Write any lasting notes to memory/YYYY-MM-DD.md..." } } } }}何时写入记忆
配置建议
小型语料库:
{ "provider": "openai", "query": { "hybrid": { "enabled": false } }}大型语料库 + 每日笔记:
{ "provider": "openai", "remote": { "batch": { "enabled": true } }, "query": { "hybrid": { "enabled": true, "mmr": { "enabled": true, "lambda": 0.7 }, "temporalDecay": { "enabled": true, "halfLifeDays": 30 } } }}完全本地:
{ "provider": "local", "fallback": "none", "local": { "modelPath": "hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF" }}Embedding 缓存
{ "cache": { "enabled": true, "maxEntries": 50000 }}好处:
sqlite-vec 加速
{ "store": { "vector": { "enabled": true, "extensionPath": "/path/to/sqlite-vec" } }}好处:
# 查看状态openclaw memory status# 强制同步openclaw memory sync --force# 检查配置openclaw config get agents.defaults.memorySearch
OpenClaw 的记忆管理系统是一个生产级的混合记忆解决方案,核心优势:
这个设计体现了现代 AI Agent 记忆管理的最佳实践:让文件成为真相,让索引成为加速器。
3.10 Skills 模块详解
Skills 模块位于 src/agents/skills/,是 OpenClaw Agent 能力扩展的核心模块。
Skill = 一个封装了特定能力的 Markdown 文件 (SKILL.md),包含:
src/agents/skills/├── types.ts # 类型定义├── config.ts # 配置解析与过滤├── workspace.ts # 核心加载逻辑├── frontmatter.ts # SKILL.md 解析├── filter.ts # 技能过滤器├── bundled-dir.ts # 内置技能目录解析├── bundled-context.ts # 内置技能缓存├── plugin-skills.ts # 插件技能集成├── refresh.ts # 文件监听与版本刷新├── env-overrides.ts # 环境变量注入├── serialize.ts # 并发控制锁├── tools-dir.ts # 工具目录路径└── skills-install.ts # 技能安装器
// workspace.ts:369-388extra → bundled → managed → agents-skills-personal → agents-skills-project → workspace
type SkillEntry = { skill: Skill; frontmatter: ParsedSkillFrontmatter; metadata?: OpenClawSkillMetadata; invocation?: SkillInvocationPolicy;};type OpenClawSkillMetadata = { always?: boolean; skillKey?: string; primaryEnv?: string; emoji?: string; os?: string[]; requires?: { bins?: string[]; env?: string[]; config?: string[]; }; install?: SkillInstallSpec[];};type SkillSnapshot = { prompt: string; skills: Array<{ name, primaryEnv, requiredEnv }>; skillFilter?: string[]; resolvedSkills?: Skill[]; version?: number;};// config.ts:70-101shouldIncludeSkill() 检查:1. config.skills.entries[skillKey].enabled !== false2. bundled allowlist 检查3. 运行时资格评估: - OS 兼容性 - 二进制依赖 - 环境变量依赖 - 配置路径检查
---name: githubdescription: "GitHub operations via `gh` CLI..."metadata: openclaw: emoji: "🐙" requires: bins: ["gh"] install: - id: brew kind: brew formula: gh bins: ["gh"]---# GitHub Skill...使用说明...
// skills.ts 导出loadWorkspaceSkillEntries() // 加载技能条目buildWorkspaceSkillSnapshot() // 构建快照(含 prompt)buildWorkspaceSkillsPrompt() // 生成 Agent promptfilterWorkspaceSkillEntries() // 过滤技能buildWorkspaceSkillCommandSpecs() // 生成命令规格syncSkillsToWorkspace() // 同步到沙箱applySkillEnvOverrides() // 注入环境变量
// types.ts:3-17type SkillInstallSpec = { kind: "brew" | "node" | "go" | "uv" | "download"; formula?: string; // brew formula package?: string; // npm/go/uv 包名 module?: string; // go module url?: string; // download URL // ...};// refresh.tsensureSkillsWatcher() // 监听 SKILL.md 变更 → bumpSkillsSnapshotVersion() // 版本号递增 → 事件通知 listeners
3.11 Session 管理
┌─────────────────────────────────────────────────────────────────┐│ 会话管理层级 │├─────────────────────────────────────────────────────────────────┤│ Session Key(身份标识) ││ ↓ ││ Session Entry(会话元数据) ││ ↓ ││ Session Store(持久化存储) ││ ↓ ││ Transcript File(对话历史) │└─────────────────────────────────────────────────────────────────┘
1. 会话键格式规范
基础格式: agent:<agentId>:<rest>示例:- agent:main:main # 默认 agent 的主会话- agent:ops:work # ops agent 的主会话- agent:main:telegram:direct:user123 # Telegram DM 会话- agent:main:discord:group:guild789 # Discord 群组会话- agent:main:cron:daily-backup:run:uuid # Cron 任务运行会话- agent:main:subagent:child-session # 子代理会话
2. 会话键解析(session-key-utils.ts:12-32)
function parseAgentSessionKey(sessionKey: string | undefined | null): ParsedAgentSessionKey | null { // 1. 规范化:小写、去空格 const raw = (sessionKey ?? "").trim().toLowerCase(); // 2. 验证最小结构 (agent:id:rest) const parts = raw.split(":").filter(Boolean); if (parts.length < 3 || parts[0] !== "agent") return null; // 3. 提取 agentId 和 rest return { agentId: parts[1], rest: parts.slice(2).join(":") };}3. 会话类型判断
核心字段(config/sessions/types.ts 相关)
type SessionEntry = { // === 身份标识 === sessionId: string; // UUID,关联对话历史文件 sessionFile?: string; // 自定义会话文件路径 // === 模型配置 === model?: string; // 当前运行时模型 modelProvider?: string; // 当前运行时提供商 modelOverride?: string; // 用户指定的模型覆盖 providerOverride?: string;// 用户指定的提供商覆盖 contextTokens?: number; // 上下文窗口大小 // === Token 统计 === totalTokens?: number; // 总 token 数 inputTokens?: number; // 输入 token outputTokens?: number; // 输出 token totalTokensFresh?: boolean; // token 数据是否新鲜 // === 投递路由 === lastChannel?: string; // 最后使用的通道 lastTo?: string; // 最后发送目标 lastAccountId?: string; // 最后账号 ID lastThreadId?: string; // 最后线程 ID deliveryContext?: DeliveryContext; // 投递上下文 // === 会话状态 === updatedAt?: number; // 最后更新时间戳 systemSent?: boolean; // 系统消息是否已发送 abortedLastRun?: boolean; // 上次运行是否中断 // === 行为配置 === thinkingLevel?: string; // 思考级别 verboseLevel?: string; // 详细级别 reasoningLevel?: string; // 推理级别 sendPolicy?: string; // 发送策略 // === 群组/频道元数据 === chatType?: "direct" | "group" | "channel"; channel?: string; // 来源通道 subject?: string; // 主题/名称 groupId?: string; // 群组 ID groupChannel?: string; // 频道名称 space?: string; // 空间/工作区 // === 显示 === displayName?: string; // 显示名称 label?: string; // 用户标签 // === 线程/派生 === forkedFromParent?: boolean; // 是否从父会话派生 spawnedBy?: string; // 创建来源 // === 压缩状态 === compactionCount?: number; // 压缩次数 memoryFlushAt?: number; // 内存刷新时间};1. 会话初始化流程(auto-reply/reply/session.ts:165-579)
┌─────────────────────────────────────────────────────────────────┐│ 会话初始化流程 │├─────────────────────────────────────────────────────────────────┤│ 1. 解析 Agent ID ││ resolveSessionAgentId({ sessionKey, config }) ││ ││ 2. 加载会话存储 ││ loadSessionStore(storePath, { skipCache: true }) ││ ││ 3. 检查重置触发器 ││ 匹配 /new, /reset 等命令 ││ ││ 4. 评估会话新鲜度 ││ evaluateSessionFreshness({ updatedAt, now, policy }) ││ ││ 5. 处理线程派生 (可选) ││ forkSessionFromParent() ││ ││ 6. 持久化会话文件 ││ resolveAndPersistSessionFile() ││ ││ 7. 归档旧会话 (重置时) ││ archiveSessionTranscripts() ││ ││ 8. 触发插件钩子 ││ hookRunner.runSessionStart() / runSessionEnd() │└─────────────────────────────────────────────────────────────────┘2. 重置触发器机制 (auto-reply/reply/session.ts:249-273)
// 默认重置触发器const DEFAULT_RESET_TRIGGERS = ["/new", "/reset"];// 匹配逻辑for (const trigger of resetTriggers) {if (trimmedBodyLower === triggerLower) {isNewSession = true;bodyStripped = ""; // 清空消息体resetTriggered = true;}// 支持带参数的重置: "/new 你好"if (strippedForResetLower.startsWith(triggerPrefixLower)) {isNewSession = true;bodyStripped = strippedForReset.slice(trigger.length).trimStart();resetTriggered = true;}}
3. 会话新鲜度策略 (config/sessions/reset.ts 相关)
type ResetPolicy = {direct: number; // DM 会话过期时间 (小时)group: number; // 群组会话过期时间thread: number; // 线程会话过期时间};// 默认策略const DEFAULT_RESET_HOURS = { direct: 24, group: 4, thread: 24 };// 评估函数function evaluateSessionFreshness(params: {updatedAt: number;now: number;policy: ResetPolicy;}): { fresh: boolean; reason?: string };
4. 线程派生机制 (auto-reply/reply/session.ts:123-163)
// 当父会话 token 过多时跳过派生,避免上下文溢出const DEFAULT_PARENT_FORK_MAX_TOKENS = 100_000;function forkSessionFromParent(params: {parentEntry: SessionEntry;agentId: string;sessionsDir: string;}): { sessionId: string; sessionFile: string } | null {// 1. 打开父会话管理器const manager = SessionManager.open(parentSessionFile);// 2. 创建分支会话const sessionFile = manager.createBranchedSession(leafId);// 3. 或创建新的派生会话文件const header = {type: "session",version: CURRENT_SESSION_VERSION,id: sessionId,parentSession: parentSessionFile, // 链接到父会话};}
1. 存储结构(gateway/session-utils.ts:575-618)
~/.openclaw/├── agents/│ ├── main/sessions.json # main agent 的会话存储│ ├── ops/sessions.json # ops agent 的会话存储│ └── ...└── sessions.json # 全局存储 (旧版兼容)
2. 多 Agent 存储合并(gateway/session-utils.ts:575-618)
function loadCombinedSessionStoreForGateway(cfg: OpenClawConfig): { storePath: string; store: Record<string, SessionEntry>;} { // 模板路径: 支持每个 agent 独立存储 if (isStorePathTemplate(storeConfig)) { for (const agentId of agentIds) { const storePath = resolveStorePath(storeConfig, { agentId }); const store = loadSessionStore(storePath); // 合并到 combined,以 canonicalKey 为键 } } // 单一文件: 所有 agent 共享存储 else { // 直接加载,规范化键名 }}3. 键名规范化与遗留键清理(gateway/session-utils.ts:237-260)
// 清理大小写不一致的遗留键function pruneLegacyStoreKeys(params: { store: Record<string, unknown>; canonicalKey: string; candidates: Iterable<string>;}) { // 1. 收集所有需要删除的键 for (const candidate of candidates) { if (candidate !== canonicalKey) { keysToDelete.add(candidate); } // 2. 查找大小写变体 for (const legacyKey of findStoreKeysIgnoreCase(store, candidate)) { if (legacyKey !== canonicalKey) { keysToDelete.add(legacyKey); } } } // 3. 批量删除 for (const key of keysToDelete) { delete store[key]; }}Cron 会话清理器策略(cron/session-reaper.ts:57-156)
// 清理策略const DEFAULT_RETENTION_MS = 24 * 3_600_000; // 24 小时const MIN_SWEEP_INTERVAL_MS = 5 * 60_000; // 最小清理间隔 5 分钟async function sweepCronRunSessions(params: {cronConfig?: CronConfig;sessionStorePath: string;}): Promise<ReaperResult> {// 1. 节流检查if (now - lastSweepAtMs < MIN_SWEEP_INTERVAL_MS) {return { swept: false, pruned: 0 };}// 2. 遍历存储,删除过期 cron 运行会话for (const key of Object.keys(store)) {if (isCronRunSessionKey(key) && entry.updatedAt < cutoff) {delete store[key];pruned++;}}// 3. 归档关联的对话文件archiveSessionTranscripts({ sessionId, reason: "deleted" });}
1. 投递信息持久化(channels/session.ts:21-58)
async function recordInboundSession(params: { storePath: string; sessionKey: string; ctx: MsgContext; updateLastRoute?: InboundLastRouteUpdate;}): Promise<void> { // 1. 记录入站消息元数据 await recordSessionMetaFromInbound({ storePath, sessionKey: canonicalSessionKey, ctx, groupResolution, }); // 2. 更新投递路由 await updateLastRoute({ storePath, sessionKey: targetSessionKey, deliveryContext: { channel: update.channel, to: update.to, accountId: update.accountId, threadId: update.threadId, }, });}2. 投递路由解析(auto-reply/reply/session.ts:60-87)
function resolveLastChannelRaw(params: { originatingChannelRaw?: string; persistedLastChannel?: string; sessionKey?: string;}): string | undefined { // 内部 webchat/系统消息不应覆盖已知的外部投递路由 if (originatingChannel === INTERNAL_MESSAGE_CHANNEL) { // 优先使用已持久化的外部通道 if (persistedChannel && isDeliverableMessageChannel(persistedChannel)) { return persistedChannel; } // 回退到 sessionKey 中编码的通道提示 if (sessionKeyChannelHint && isDeliverableMessageChannel(sessionKeyChannelHint)) { return sessionKeyChannelHint; } }}3.12 自进化机制
OpenClaw 通过以下几个核心机制实现自我更新与进化:
工作区包含可编辑的文件,agent 可在对话中修改:
每次运行时动态构建系统提示,包括:
当文件被修改后,下次会话立即反映变化。
Agent 内置 read/write/edit 工具,可以:
系统提示包含 OpenClaw Self-Update 部分,agent 可以运行:
用户指令/反馈 → Agent 修改文件 → 下次会话加载新内容 → 行为改变 → 持续迭代
这种设计让 agent 能够像人类一样"学习"和"成长",通过文件系统持久化进化成果。
3.13 工作区与 Agent 路由
工作区是代理的文件系统级隔离环境,包含代理的引导文件、记忆、身份和工具配置。
核心特性
1. 目录结构
3. 初始化流程
.openclaw/workspace-state.json)4. 子代理过滤
路由系统决定哪个代理处理哪个消息,是 OpenClaw 多代理架构的核心。
路由层次结构(从高到低优先级)
const tiers = [ { matchedBy: "binding.peer", ... }, // 1. 精确对等匹配 { matchedBy: "binding.peer.parent", ... }, // 2. 父对等匹配(线程) { matchedBy: "binding.guild+roles", ... }, // 3. 公会+角色匹配 { matchedBy: "binding.guild", ... }, // 4. 公会匹配 { matchedBy: "binding.team", ... }, // 5. 团队匹配 { matchedBy: "binding.account", ... }, // 6. 账户匹配 { matchedBy: "binding.channel", ... }, // 7. 频道匹配 { matchedBy: "default", ... } // 8. 默认代理];路由匹配规则详解
用于线程继承
当消息来自线程但线程本身无绑定时,检查父频道绑定
确保 Discord 论坛主题能继承父频道路由
guildId 和 roles 约束Discord 公会级匹配(无角色要求)
示例:公会 g1 的所有消息路由到代理 guild
Slack 特有
匹配 Slack 工作区(团队)
无任何绑定匹配时使用
路由到配置中的 defaultAgentId(默认为 main)
绑定配置示例
const bindings = [ // 精确对等绑定 { agentId: "support", match: { channel: "whatsapp", accountId: "biz", peer: { kind: "direct", id: "+1234567890" } } }, // 公会绑定 { agentId: "community", match: { channel: "discord", guildId: "123456789" } }, // 角色绑定 { agentId: "admin", match: { channel: "discord", guildId: "123456789", roles: ["admin", "moderator"] } }];会话键决定对话历史如何隔离和持久化。
DM 作用域类型
type DmScope = | "main" // 所有 DM 共享一个会话 | "per-peer" // 每个对等有独立会话 | "per-channel-peer" // 每个频道+对等组合独立 | "per-account-channel-peer"; // 每个账户+频道+对等组合独立
会话键格式
agent:{agentId}:{mainKey} // 主会话agent:{agentId}:direct:{peerId} // per-peer DMagent:{agentId}:{channel}:direct:{peerId} // per-channel-peer DMagent:{agentId}:{channel}:{accountId}:direct:{peerId} // per-account-channel-peeragent:{agentId}:{channel}:{peerKind}:{peerId} // 群组/频道agent:{agentId}:{channel}:{peerKind}:{peerId}:thread:{threadId} // 线程身份链接
允许跨平台合并会话。
示例:Telegram 用户 111111111 和 Discord 用户 222222222222222222 共享身份 alice。
identityLinks: { alice: ["telegram:111111111", "discord:222222222222222222"]}场景 1:多租户 SaaS
binding 1: WhatsApp Business "company-a" -> agent "support-a"binding 2: WhatsApp Business "company-b" -> agent "support-b"
场景 2:Discord 社区管理
binding 1: Guild "123" + Role "admin" -> agent "admin-bot"binding 2: Guild "123" (no role) -> agent "community-bot"binding 3: Channel "welcome" -> agent "greeter"
场景 3:Slack 企业部署
binding 1: Team "T-sales" -> agent "sales-assistant"binding 2: Team "T-engineering" -> agent "tech-support"
场景 4:线程隔离
Parent Channel "general" -> agent "general-bot"Thread in "general" inherits parent binding
3.14 Nodes
Nodes 是 OpenClaw 的分布式设备/客户端管理架构,让 Gateway 可以远程控制和协调多个设备上的操作。
Node = 一个可执行命令的远程客户端,例如:
Node Gateway |-- node.pair.request -------------->| (发起请求) | | (加入 pending 列表) | | |<-------- 广播 node.pair.requested --| (通知管理员) | | | [管理员审批] | | | |<------- node.pair.approve ---------| (生成 token) | | |-- node.pair.verify --------------->| (验证 token) | | |<----------- 连接建立 --------------| (认证成功)
src/node-host/ 中的代码运行在远程设备上:
┌─────────────────────────────────────────────────┐│ Node Host │├─────────────────────────────────────────────────┤│ runner.ts ││ - 启动 WebSocket 客户端 ││ - 连接 Gateway ││ - 声明 caps/commands │├─────────────────────────────────────────────────┤│ invoke.ts ││ - 处理 system.run/which/browser.proxy ││ - 执行本地命令 ││ - 管理执行审批 │├─────────────────────────────────────────────────┤│ config.ts ││ - 存储 nodeId/token/gateway 配置 ││ - ~/.openclaw/node.json │└─────────────────────────────────────────────────┘
命令分类(gateway/node-command-policy.ts:56)
安全策略
当 Node 离线时自动唤醒 (gateway/server-methods/nodes.ts:89):
1. maybeWakeNodeWithApns()├── 检查 APNS 注册├── 发送后台唤醒通知└── 等待重连 (3s)2. 如果仍离线,重试一次└── 发送后台唤醒 + 等待 (12s)3. 如果仍离线└── maybeSendNodeWakeNudge()└── 发送可见提醒:"OpenClaw needs a quick reopen"
Node 可向 Gateway 发送事件 (gateway/server-node-events.ts:247):
客户端 → Gateway.node.invoke({nodeId, command, params}) │ ├── 检查节点是否连接 │ └── 未连接 → APNS 唤醒 │ ├── 命令策略检查 │ └── node-command-policy.ts │ ├── NodeRegistry.invoke() │ └── WebSocket 发送 node.invoke.request │ └── Node Host 处理 ├── invoke.ts 路由到具体 handler ├── 执行命令 (spawn + 安全检查) └── 返回 node.invoke.result3.15 安全策略
核心原则:OpenClaw 采用"个人助手"模型,不是多租户共享总线。
单用户信任模型:┌─────────────────────────────────────┐│ 一个可信操作者 ││ ├── 一个 Gateway ││ │ └── 多个 Agent ││ └── 多个会话(sessionKey 是路由控制,不是授权边界)└─────────────────────────────────────┘
关键点:
插件以进程内方式加载,与 Gateway 同等权限:
插件 = 可信代码├── 可以读取环境变量/文件├── 可以执行主机命令└── 与 Gateway 进程权限相同
安全报告必须证明边界绕过(如未认证加载、策略绕过),而不是"恶意插件执行了特权操作"。
agents.defaults.sandbox.mode: off # 默认关闭沙箱tools.exec.host: sandbox # 路由偏好,但沙箱未激活时在主机执行
含义:默认情况下,命令执行在主机上进行,因为操作者已受信任。
信任边界:├── 主机 OS/管理员边界 = 信任边界├── 能修改 ~/.openclaw 的人 = 可信操作者└── 推荐模式:一用户一主机/VPS一Gateway
# 推荐:仅绑定回环地址gateway.bind="loopback" # 默认值openclaw gateway run --bind loopback# 远程访问方案:# 1. SSH 隧道# 2. Tailscale serve/funnel# 3. 不要直接暴露到公网
# 推荐tools.exec.applyPatch.workspaceOnly: true # 限制写入到工作区# 可选tools.fs.workspaceOnly: true # 限制所有文件操作到工作区
总结:OpenClaw 的安全模型基于"可信操作者"假设,核心是主机信任 + Gateway 认证,不提供多租户隔离。安全报告需要证明边界绕过,而非展示已授权/可信场景下的行为。
3.16 配置管理
配置管理采用分层架构,核心模块位于 src/config/:
src/config/├── io.ts # 配置I/O核心引擎├── paths.ts # 路径解析策略├── validation.ts # 多层验证框架├── zod-schema.ts # Zod模式定义├── defaults.ts # 运行时默认值应用├── includes.ts # $include模块化支持├── env-substitution.ts # 环境变量替换└── types.ts # TypeScript类型聚合
配置文件格式与位置
JSON5 格式,支持注释和尾随逗号:
// 支持环境变量{ "models": { "providers": { "anthropic": { "apiKey": "${ANTHROPIC_API_KEY}" // 运行时替换 } } }}路径解析优先级(paths.ts:130-183):
配置生命周期
加载 → 解析 → 合并 → 验证 → 应用默认值 → 缓存
关键实现(io.ts:682-818):
function loadConfig(): OpenClawConfig { // 1. 读取原始JSON5文件 const raw = deps.fs.readFileSync(configPath, "utf-8"); const parsed = deps.json5.parse(raw); // 2. 解析$include指令 const resolved = resolveConfigIncludesForRead(parsed, configPath, deps); // 3. 环境变量替换 const { resolvedConfigRaw } = resolveConfigForRead(resolved, deps.env); // 4. 验证与默认值 const validated = validateConfigObjectWithPlugins(resolvedConfigRaw); const cfg = applyModelDefaults(applyAgentDefaults(validated.config)); // 5. 路径规范化 normalizeConfigPaths(cfg); return cfg;}设计目标
支持大型部署的配置拆分,实现关注点分离。
// openclaw.json{ "$include": [ "./models/anthropic.json5", "./channels/telegram.json5" ], "gateway": { "mode": "remote" }}安全实现
路径遍历防护(includes.ts:198-222):
// 拒绝访问配置目录外的文件if (!isPathInside(this.rootDir, normalized)) {thrownew ConfigIncludeError(`Include path escapes config directory: ${includePath}`,includePath);}// 解析符号链接并重新验证const real = fs.realpathSync(normalized);if (!isPathInside(this.rootRealDir, real)) {thrownew ConfigIncludeError(`Include path resolves outside config directory (symlink)`,includePath);}
合并策略
深度合并算法(includes.ts:70-85):
export function deepMerge(target: unknown, source: unknown): unknown { if (Array.isArray(target) && Array.isArray(source)) { return [...target, ...source]; // 数组连接 } if (isPlainObject(target) && isPlainObject(source)) { const result = { ...target }; for (const key of Object.keys(source)) { result[key] = key in result ? deepMerge(result[key], source[key]) // 递归合并 : source[key]; } return result; } return source; // 原始类型: 后值覆盖前值}多层验证架构
// 验证流水线validateConfigObjectWithPlugins(raw) → validateConfigObjectRaw(raw) // 1. 基础Zod验证 → findLegacyConfigIssues(raw) // 2. 历史配置检查 → findDuplicateAgentDirs(config) // 3. Agent目录冲突检测 → validateIdentityAvatar(config) // 4. Avatar路径安全验证 → validatePluginSchemas(config) // 5. 插件配置验证
Zod Schema 设计
严格模式 + 细粒度校验 (zod-schema.ts):
exportconst OpenClawSchema = z.object({ // 元数据自动时间戳处理 meta: z.object({ lastTouchedAt: z.union([ z.string(), z.number().transform((n, ctx) => { const d = new Date(n); if (Number.isNaN(d.getTime())) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Invalid timestamp" }); return z.NEVER; } return d.toISOString(); }) ]).optional() }).strict().optional(), // Gateway配置 gateway: z.object({ mode: z.union([z.literal("local"), z.literal("remote")]).optional(), auth: z.object({ mode: z.union([ z.literal("none"), z.literal("token"), z.literal("password"), z.literal("trusted-proxy") ]).optional(), token: z.string().optional().register(sensitive) // 敏感值标记 }).strict().optional() }).strict().optional(), // 跨字段验证}).superRefine((cfg, ctx) => { // 验证broadcast中的agentId是否存在于agents.list const agentIds = new Set(cfg.agents?.list?.map(a => a.id) ?? []); for (const [peerId, ids] of Object.entries(cfg.broadcast ?? {})) { for (const agentId of ids) { if (!agentIds.has(agentId)) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["broadcast", peerId], message: `Unknown agent id "${agentId}"` }); } } }});插件配置验证
动态Schema加载 (validation.ts:418-438):
for (const record of registry.plugins) { const pluginId = record.id; const entry = normalizedPlugins.entries[pluginId]; if (record.configSchema) { const res = validateJsonSchemaValue({ schema: record.configSchema, cacheKey: record.schemaCacheKey ?? pluginId, value: entry?.config ?? {} }); if (!res.ok) { issues.push({ path: `plugins.entries.${pluginId}.config`, message: `invalid config: ${res.errors.join(", ")}` }); } }}双阶段替换
读取时替换(io.ts:652-666):
function resolveConfigForRead(resolvedIncludes, env){ // 1. 应用config.env到process.env applyConfigEnvVars(resolvedIncludes, env); // 2. 替换${VAR}引用 return { resolvedConfigRaw: resolveConfigEnvVars(resolvedIncludes, env), envSnapshotForRestore: { ...env } // 保存快照用于回写 };}写入时恢复:
// 写入前恢复原始的${VAR}引用cfgToWrite = restoreEnvVarRefs( cfgToWrite, parsedRes.parsed, // 原始文件内容 envForRestore // 读取时的环境变量快照);设计原则
不持久化默认值 - 只在加载时应用,写入时剥离。
// 加载时应用默认值const cfg = applyModelDefaults(applyAgentDefaults(applySessionDefaults(validated.config)));// 写入时不包含运行时默认值const stampedOutputConfig = stampConfigVersion(outputConfig);// 不调用 applyModelDefaults
关键默认值
Model 默认值(defaults.ts:213-347):
Agent 默认值(defaults.ts:349-388):
Session 默认值(defaults.ts:144-168):
配置缓存
短期缓存策略(io.ts:1292-1374):
const DEFAULT_CONFIG_CACHE_MS = 200; // 200ms TTLexport function loadConfig(): OpenClawConfig {// 检查运行时快照if (runtimeConfigSnapshot) {return runtimeConfigSnapshot;}// 检查缓存const cached = configCache;if (cached && cached.configPath === configPath && cached.expiresAt > now) {return cached.config;}// 加载并更新缓存const config = io.loadConfig();configCache = {configPath,expiresAt: now + cacheMs,config};return config;}
禁用缓存: OPENCLAW_DISABLE_CONFIG_CACHE=1
写入审计
安全审计日志 (io.ts:1178-1228):
const auditRecord = {ts: new Date().toISOString(),event: "config.write",result: "rename" | "copy-fallback" | "failed",configPath,previousHash,nextHash,previousBytes,nextBytes,changedPathCount,suspicious: ["size-drop", // 大小骤降50%+"missing-meta-before-write","gateway-mode-removed"],pid, ppid, cwd, argv};await appendConfigWriteAuditRecord(deps, auditRecord);
友好错误消息
DM策略错误提示 (io.ts:148-167):
function formatConfigValidationFailure(pathLabel, issueMessage){ const match = issueMessage.match(OPEN_DM_POLICY_ALLOW_FROM_RE); if (!match) return `Config validation failed: ${pathLabel}: ${issueMessage}`; return [ `Configuration mismatch: ${policyPath} is "open", but ${allowPath} does not include "*".`, "", "Fix with:", ` openclaw config set ${allowPath} '["*"]'`, "", "Or switch policy:", ` openclaw config set ${policyPath} "pairing"` ].join("\n");}历史配置检测
迁移警告 (legacy.ts):
export function findLegacyConfigIssues(raw: unknown): LegacyConfigIssue[] { const issues: LegacyConfigIssue[] = []; // 检测已移除的配置项 if (raw.routing?.allowFrom) { issues.push({ path: "routing.allowFrom", message: "routing.allowFrom is removed. Use routing.channels.*.dm.policy instead." }); } // 检测废弃的命名 if (raw.gateway?.token) { issues.push({ path: "gateway.token", message: 'Use "gateway.auth.token" instead.' }); } return issues;}原型污染防护
Blocked Keys(prototype-keys.ts):
exportconst BLOCKED_OBJECT_KEYS = new Set(["__proto__","constructor","prototype"]);export function isBlockedObjectKey(key: string): boolean {return BLOCKED_OBJECT_KEYS.has(key);}
敏感值处理
Zod 敏感值标记(zod-schema.sensitive.ts):
exportconst sensitive = Symbol("sensitive");export function redactSensitiveValues(config: unknown): unknown {// 递归遍历配置对象// 替换标记为sensitive的值为"[REDACTED]"}
文件权限
安全默认值(io.ts:1236-1240):
// 目录权限: 0o700 (仅所有者可访问)await fs.promises.mkdir(dir, { recursive: true, mode: 0o700 });// 文件权限: 0o600 (仅所有者可读写)await fs.promises.writeFile(tmp, json, { encoding: "utf-8", mode: 0o600 });
插件配置 Schema
动态加载(plugins/config-schema.ts)
export interface PluginConfigSchema { id: string; kind: "channel" | "memory" | "tool" | "skill"; configSchema?: JSONSchema; channels?: string[];}运行时覆盖
测试与诊断场景(runtime-overrides.ts):
export function applyConfigOverrides(config: OpenClawConfig): OpenClawConfig { // 允许通过环境变量覆盖特定配置项 // 例如: OPENCLAW_OVERRIDE_gateway_mode=local return config;}四、总结展望
2025 年个人效率工具在编程、办公领域得到了极大的发展与提升,2026 年作为企业智能元年,可以预见会出来更多的企业级智能体,这些智能体将朝着更加分布式、安全可控且深度集成业务流程的方向演进。
4.1 架构方向演进
1. 控制平面与执行节点的解耦 (Decoupling Control & Execution)
企业架构将采用类似的“中枢管理 + 边缘执行”模式。总部部署中央控制平面负责权限审核、配置同步和任务路由,而执行节点则部署在员工终端、内部服务器或特定硬件设备上,确保数据在企业内网中闭环处理。
2. 多智能体协作网络 (Multi-Agent Networking)
企业内部将不再是单一的“万能助手”,而是由多个专业化智能体(如 HR 助手、财务助手、IT 运维助手)构成的网络。它们通过标准化的 RPC 协议或内部会话协议进行信息共享和任务接力,形成复杂的自动化流水线。
3. 软硬件深层权限管理 (Hardware & Permission Integration)
企业级 Agent 将深入集成到办公硬件(如会议室系统、扫码枪、PDA)。架构设计上将包含更精细的 TCC(透明度、同意和控制)策略,确保 Agent 在执行敏感操作(如调用公司摄像头或执行系统脚本)时受到严格的合规性审计。
4.2 应用方向演进
1. 全渠道业务渗透 (Omnichannel Business Integration)
企业 Agent 将无缝嵌入到所有内部协作工具中,打破“信息孤岛”。Agent 不仅能回答问题,还能直接在通讯软件中通过 Discord/Slack 动作或自动触发工作流来处理审批、请假或订单更新,实现“对话即办公”。
2. 动态可视化协同工作区 (Live Visual Collaboration)
在复杂的企业决策场景(如供应链管理或数据分析)中,Agent 将利用类似 Canvas 的技术提供动态可视化面板。团队成员可以与 Agent 在同一画布上进行交互式修改,Agent 实时生成数据图表或拓扑图,大幅提升决策效率。
3. 基于沙箱的安全生产环境 (Sandboxed Production Environment)
企业将普遍采用“隔离运行环境”。当 Agent 处理外部客户询价或不受信任的输入时,系统会自动将其放入临时的、受限的容器中执行,防止恶意脚本通过 Agent 渗透进企业核心数据库或内部网络。
4. 企业级“技能中心” (Enterprise Skill Hubs)
企业将建立私有的技能注册表。员工可以为自己的 Agent 订购经 IT 部门认证的“技能包”(如 ERP 插件、专业财务计算器等)。Agent 会根据当前任务上下文,自动从企业私有云拉取并挂载这些技能,实现功能的动态扩展。
未来的企业级智能体将借鉴 OpenClaw 的 Local-first(数据私有)和 Gateway/Node(控制与执行分离)理念,在保证数据所有权(Own your data)的前提下,通过多智能体协作和深度的软硬件集成,成为企业数字化转型的核心基础设施
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-06-30
运维界的 OpenClaw 来了!
2026-06-30
刚刚,OpenClaw和Cursor杀入手机!Agent从此塞进口袋
2026-06-21
openclaw深度实践(四种场景:企业提效参考)
2026-06-21
OpenClaw不仅仅是聊天框,还是Agent后台引擎,通过API接入现有平台
2026-06-18
OpenClaw MetaSKILLs 系统深度解析:AI Agent 正在学会「自己给自己写技能」
2026-06-17
OpenClaw 6.8 震撼发布:不堆噱头,彻底治愈 Agent 的“宕机失忆症”
2026-06-01
OpenClaw 5月28日更新:更加提升稳定性
2026-05-31
Claw Team 在 SRE 场景下的实践
2026-04-09
2026-04-03
2026-04-15
2026-05-03
2026-04-09
2026-04-13
2026-04-18
2026-04-04
2026-04-08
2026-05-29
2026-04-09
2026-04-07
2026-04-02
2026-03-30
2026-03-30
2026-03-26
2026-03-24
2026-03-24
欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。
在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。
一、 定义
本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。
会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。
知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。
二、 账号注册与登录
登录方式:本网站支持以下登录方式,您可根据实际情况选择:
微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。
手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。
账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。
实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。
未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。
三、 服务内容与规范
知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。
服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。
禁止行为:您在使用服务时不得实施以下行为:
利用技术手段批量爬取、下载、转存知识库内容;
将知识库内容用于商业目的或未经授权地向第三方传播;
干扰本网站正常运行或侵犯其他用户合法权益;
发布违法违规信息或从事违反公序良俗的活动。
四、 知识产权声明
权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。
有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。
侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。
五、 个人信息保护
我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。
您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。
您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。
六、 免责声明
内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。
不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。
第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。
七、 违约责任
如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。
如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。
八、 法律适用与争议解决
本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。
因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。
九、 其他
本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。
本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。
我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。