目录
【Claude】Claude Code 沙箱(Sandbox)机制深度解析
/    

【Claude】Claude Code 沙箱(Sandbox)机制深度解析

GeminiGeneratedImagevraptivraptivrap.png

Claude Code 沙箱(Sandbox)机制深度解析

1. 沙箱的目标与定位

Claude Code 的沙箱是一个 OS 级别的命令隔离机制,目标是将 AI 执行的 Bash 命令限制在安全的边界内,防止:

  • 🔒 文件系统越权写入(修改 settings、植入恶意 skills 等)
  • 🌐 网络请求逃逸(访问未授权的域名/服务)
  • 🐚 命令注入攻击(通过 git bare repo 等间接逃逸)

[!IMPORTANT]
沙箱不是应用层的权限检查(那是 Permission System),而是底层 OS 沙箱包装器,在 macOS 上使用 sandbox-exec,Linux 上使用 bubblewrap (bwrap) + seccomp


2. 整体架构

graph TB
    subgraph "用户层"
        A["/sandbox 命令"] --> B["SandboxSettings UI"]
        C["Settings JSON<br>sandbox.enabled"] --> D["SandboxManager"]
    end
    
    subgraph "核心适配层"
        D --> E["sandbox-adapter.ts<br>(Claude CLI 适配器)"]
        E --> F["@anthropic-ai/sandbox-runtime<br>(底层运行时)"]
    end
    
    subgraph "工具集成层"
        G["BashTool"] --> H["shouldUseSandbox()"]
        H --> I["wrapWithSandbox()"]
        I --> F
    end
    
    subgraph "安全控制"
        J["文件系统限制"] --> E
        K["网络域名白名单"] --> E
        L["违规事件监控"] --> E
        M["Git bare repo 防护"] --> E
    end
    
    subgraph "UI 反馈"
        N["SandboxViolationExpandedView"]
        O["SandboxPermissionRequest"]
        P["SandboxDoctorSection"]
    end
    
    F --> N
    F --> O

3. 核心模块详解

3.1 类型定义层 — sandboxTypes.ts

📝 文件: sandboxTypes.ts

这是沙箱配置的 单一数据源(Single Source of Truth),使用 Zod schema 定义了三个核心配置结构:

Schema用途
SandboxNetworkConfigSchema网络隔离配置:允许的域名、Unix Socket、本地绑定、代理端口
SandboxFilesystemConfigSchema文件系统配置:读写白名单/黑名单路径
SandboxSettingsSchema顶层沙箱配置:启用开关、自动允许、排除命令列表等

关键设计点:

// 网络层 — 支持企业级管控
allowManagedDomainsOnly  // 企业模式:只允许托管域名
allowUnixSockets         // macOS 专有:Unix socket 白名单
httpProxyPort            // HTTP 代理端口(MITM 代理支持)

// 文件系统层 — 分层权限
allowWrite / denyWrite   // 写入白名单/黑名单
denyRead / allowRead     // 读取黑名单/白名单(allowRead 优先于 denyRead)

// 顶层开关
enabled                        // 主开关
failIfUnavailable              // 严格模式(企业部署用)
autoAllowBashIfSandboxed       // 沙箱内自动批准 Bash 命令
allowUnsandboxedCommands       // 是否允许跳出沙箱
excludedCommands               // 排除命令列表(非安全边界)
enableWeakerNetworkIsolation   // macOS: 放松 trustd 限制(Go CLI 兼容)

3.2 核心适配器 — sandbox-adapter.ts

📝 文件: sandbox-adapter.ts

这是沙箱系统的 最核心文件(~986行),作为 Claude CLI 与底层 @anthropic-ai/sandbox-runtime 之间的桥接层。主要职责:

3.2.1 配置转换:convertToSandboxRuntimeConfig()

将 Claude Code 的 settings 格式转换为沙箱运行时理解的 SandboxRuntimeConfig

Claude Code Settings ──> convertToSandboxRuntimeConfig() ──> SandboxRuntimeConfig

网络域名提取

  • permissions.allow 中提取 WebFetch(domain:xxx) 规则 → 加入 allowedDomains
  • permissions.deny 中提取 → 加入 deniedDomains
  • 支持 allowManagedDomainsOnly 企业模式

文件系统路径构建

  • 默认可写:当前目录 . + Claude 临时目录
  • 安全硬编码:始终 deny settings.json 和 managed settings 的写入
  • 安全硬编码:始终 deny .claude/skills 的写入(防止技能注入)
  • Edit(path) 权限规则提取可写路径
  • Read(path) 权限规则提取读取限制
  • 支持 --add-dir 的额外目录
  • 处理 Git worktree 的主仓库路径

3.2.2 路径解析规则

两套不同的路径语义:

路径前缀Permission Rules 中的含义sandbox.filesystem 中的含义
//path绝对路径 (/path)绝对路径 (/path)
/path相对于 settings 文件目录绝对路径(直接使用)
~/path透传给沙箱运行时展开为 home 目录
./path透传相对于 settings 文件目录

[!WARNING]
这是一个易混淆的设计。/Users/foo/.cargo 在 permissions 规则中会被错误解析为 settings 相对路径!这也是 #30067 bug fix 的原因。

3.2.3 Git Bare Repo 安全防护

攻击场景:
  攻击者在 cwd 放置 HEAD + objects/ + refs/ + hooks/ + config
  → Git 的 is_git_directory() 误认为 bare repo
  → core.fsmonitor 恶意配置被执行
  → 沙箱逃逸

防护策略(双层):

  1. 已存在的文件denyWrite (只读绑定)
  2. 不存在的文件 → 记录到 bareGitRepoScrubPaths,命令执行后立即 rmSync 清理
// sandbox-adapter.ts:404
function scrubBareGitRepoFiles(): void {
  for (const p of bareGitRepoScrubPaths) {
    try { rmSync(p, { recursive: true }) }
    catch { /* ENOENT 是正常情况 */ }
  }
}

3.2.4 初始化与配置热更新

async function initialize(sandboxAskCallback?) {
  // 1. 检查 Git worktree 路径(一次性)
  // 2. 读取 settings → 转换为 SandboxRuntimeConfig
  // 3. 调用 BaseSandboxManager.initialize()
  // 4. 订阅 settings 变更 → 自动执行 BaseSandboxManager.updateConfig()
}

[!NOTE]
配置热更新通过 settingsChangeDetector.subscribe() 实现,当用户修改 settings 时,沙箱规则实时刷新,无需重启。

3.2.5 导出的 SandboxManager 接口

export const SandboxManager: ISandboxManager = {
  // 🟢 自定义实现(Claude CLI 特有逻辑)
  initialize,
  isSandboxingEnabled,          // 综合判断:平台 + 依赖 + 设置
  getSandboxUnavailableReason,  // 诊断信息(#34044 fix)
  isAutoAllowBashIfSandboxedEnabled,
  areUnsandboxedCommandsAllowed,
  isSandboxRequired,            // failIfUnavailable
  areSandboxSettingsLockedByPolicy,
  setSandboxSettings,           // 写入 localSettings
  wrapWithSandbox,              // 包装命令
  refreshConfig,                // 立即刷新
  
  // 🔵 直接转发给底层 sandbox-runtime
  getFsReadConfig,
  getFsWriteConfig,
  getNetworkRestrictionConfig,
  getSandboxViolationStore,
  annotateStderrWithSandboxFailures,
  // ...
  
  // 🔴 特殊处理
  cleanupAfterCommand: () => {
    BaseSandboxManager.cleanupAfterCommand()
    scrubBareGitRepoFiles()  // 额外清理 bare repo 植入
  },
}

3.3 BashTool 集成 — shouldUseSandbox.ts

📝 文件: shouldUseSandbox.ts

决定一个 Bash 命令是否应该在沙箱内运行的核心逻辑:

flowchart TD
    A["shouldUseSandbox(input)"] --> B{"沙箱已启用?"}
    B -- No --> Z["return false"]
    B -- Yes --> C{"dangerouslyDisableSandbox<br>且允许跳出?"}
    C -- Yes --> Z
    C -- No --> D{"命令为空?"}
    D -- Yes --> Z
    D -- No --> E{"命令在排除列表中?"}
    E -- Yes --> Z
    E -- No --> Y["return true ✅"]

排除命令匹配 (containsExcludedCommand()) 的精妙之处:

  1. 复合命令拆分docker ps && curl evil.com 拆分后逐一检查
  2. 环境变量剥离FOO=bar bazel run → 先检查完整,再检查 bazel run
  3. 包装器剥离timeout 30 bazel runbazel run
  4. 迭代不动点:交替剥离直到没有新候选(处理 timeout 300 FOO=bar bazel run
  5. 多种匹配模式:前缀匹配、精确匹配、通配符匹配

[!NOTE]
excludedCommands用户便利功能,不是安全边界。注释明确说明:"It is not a security bug to be able to bypass excludedCommands"。真正的安全控制是沙箱权限系统本身。


3.4 底层 Stub — anthropic-sandbox-runtime.ts

📝 文件: anthropic-sandbox-runtime.ts

因为 @anthropic-ai/sandbox-runtime 是 Anthropic 内部包,源码还原版提供了一个 no-op stub

export class SandboxManager {
  static isSupportedPlatform(): boolean { return false }
  static isSandboxingEnabled(): boolean { return false }
  static async wrapWithSandbox(command: string): Promise<string> { 
    return command  // 直接返回原命令,不做任何包装
  }
  // ...全部返回空/默认值
}

[!CAUTION]
这意味着在源码还原版中,沙箱功能实际上是完全禁用的。所有命令都会 bypass 沙箱直接执行。要理解真实的沙箱行为,需要参考 adapter 层的逻辑设计。


4. UI 组件体系

4.1 沙箱设置面板 — SandboxSettings.tsx

📝 文件: SandboxSettings.tsx

通过 /sandbox 命令触发,提供三种模式选择:

模式说明
Auto-allow沙箱内自动批准,沙箱外回退到常规权限
Regular沙箱内运行,但每次仍需权限确认
Disabled完全关闭沙箱

包含 4 个 Tab 页面:

  • Mode — 模式选择
  • Dependencies — 依赖检查(sandbox-exec/bwrap 是否可用)
  • Overrides — 排除命令管理
  • Config — 当前生效的配置查看

4.2 网络权限请求 — SandboxPermissionRequest.tsx

📝 文件: SandboxPermissionRequest.tsx

当沙箱拦截到一个不在白名单中的网络请求时,弹出交互式对话框:

┌─ Network request outside of sandbox ─────┐
│ Host: api.example.com                     │
│                                           │
│ Do you want to allow this connection?     │
│ ○ Yes                                     │
│ ○ Yes, and don't ask again for api.example│
│ ○ No, and tell Claude what to do (esc)    │
└───────────────────────────────────────────┘

[!NOTE]
如果启用了 allowManagedDomainsOnly 企业策略,"don't ask again" 选项会被隐藏,用户无法自行永久放行域名。

4.3 违规事件展示 — SandboxViolationExpandedView.tsx

📝 文件: SandboxViolationExpandedView.tsx

实时展示沙箱阻止的操作,订阅 SandboxViolationStore 显示最近 10 条:

⧈ Sandbox blocked 3 total operations
  1:30:45pm npm run build: network connect to registry.npmjs.org:443
  1:30:46pm curl: network connect to evil.com:80
  … showing last 2 of 3

5. 配置传播路径

flowchart LR
    A["~/.claude/settings.json<br>(localSettings)"] --> G["getSettings_DEPRECATED()"]
    B[".claude/settings.json<br>(projectSettings)"] --> G
    C["policySettings<br>(企业托管)"] --> G
    D["flagSettings<br>(Feature Flags)"] --> G
    
    G --> H["convertToSandboxRuntimeConfig()"]
    H --> I["SandboxRuntimeConfig"]
    I --> J["BaseSandboxManager.initialize()"]
    
    K["settingsChangeDetector"] -.-> |"热更新"| H

设置优先级(高 → 低):

  1. flagSettings — Feature Flag 控制
  2. policySettings — 企业策略文件
  3. projectSettings — 项目级 .claude/settings.json
  4. localSettings — 用户级 ~/.claude/settings.local.json

6. 安全纵深防御总结

层级机制具体措施
OS 层sandbox-exec / bwrap进程级隔离,底层沙箱包装命令
文件系统路径白名单/黑名单settings.json + .claude/skills 始终 deny-write
网络域名白名单 + 代理HTTP/SOCKS proxy + 未知域名交互式询问
Git 安全Bare repo 防护已存在文件 readonly + 新文件后清理
配置锁定企业策略policySettings 覆盖本地 + failIfUnavailable
命令过滤excludedCommands复合命令拆分 + 环境变量剥离 + 包装器剥离
诊断违规监控 + Doctor实时违规展示 + 依赖检查

7. 关键源码位置索引

文件作用
sandboxTypes.ts沙箱配置 Zod Schema (SSoT)
sandbox-adapter.ts核心适配器 (986行)
shouldUseSandbox.tsBashTool 沙箱决策
anthropic-sandbox-runtime.ts底层运行时 Stub
SandboxSettings.tsx设置 UI 入口
SandboxPermissionRequest.tsx网络权限弹窗
SandboxViolationExpandedView.tsx违规事件展示
sandbox-toggle.tsx/sandbox 命令实现

标题:【Claude】Claude Code 沙箱(Sandbox)机制深度解析
作者:gitsilence
地址:https://blog.lacknb.cn/articles/2026/04/14/1776147237436.html