随笔

Claude Code 深度源码解读 08:安全边界是分层系统,不是权限弹窗

从 settings trust、tool pool、input validation、permissions、path validation、sandbox、MCP 与 remote 读安全治理。

2026-04-16 Claude Code源码解读Agent Harness技术深读

简化版入口:安全与信任边界

机制图
机制图

我的设问与回应

设问 1:安全边界是不是权限弹窗?

回应答案: 不是。权限 UI 只是 ask 分支。真实边界包括工具可见性、输入校验、PreToolUse、deny-first 权限、path validation、sandbox、MCP approval、bridge/remote gate、workspace trust、managed settings。

证据与证明路径: 证据来自第 8 期的核心流程图、关键源码入口和 5.1 安全不是只靠权限弹窗。

还值得继续学习或反思: 进一步要追的是每个外部连接面是否都有独立 auth、approval、policy 和审计。

设问 2:auto / bypass 会不会破坏安全?

回应答案: 源码把 auto/bypass 放在 deny、ask、tool check、requiresUserInteraction、safetyCheck 之后,并排除部分高风险工具或模式。projectSettings 也不能接受高风险 opt-in。

证据与证明路径: 证据来自第 8 期 5.2 与 5.3,对 permissions.ts、settings.ts 排除 projectSettings 的说明。

还值得继续学习或反思: 自动化审批只能是受限优化,不能成为最高优先级。

源码调研主体

本组解读基于冻结源码快照进行教育、防御和架构研究。

本期主题:从 permissions、sandbox、MCP、bridge、managed settings、workspace trust、hooks 和多 agent 角度复盘 Harness 如何防止 agent 稳定地做错事。

1. 研究问题

本期围绕一个问题展开:

Claude Code Harness 的安全边界到底在哪里?哪些机制负责防止模型把错误推理放大成真实副作用?

前几期已经分别分析了 Tools / Permissions、Query Loop、Hooks、Memory 和多 Agent。第 8 期不重复每条链路,而是横向复盘信任边界:

  • 模型能看到什么工具。
  • 模型产生的工具输入如何被校验。
  • 权限规则如何合并 deny / ask / allow。
  • auto / bypass / headless 场景如何避免无交互误放行。
  • 文件路径、sandbox、MCP、bridge 和 remote control 如何建立外部边界。
  • managed settings 与 workspace trust 如何防止项目配置自我提权。

本期只做防御性架构总结,不提供绕过步骤或复用实现。

2. 对应总览节点

对应第 1 期总览图中的节点:

  • Permissions
  • Tool Hooks
  • Tool.call
  • MCP
  • Bridge / Remote
  • Managed Settings
  • Sandbox
  • Transcript / Audit

这部分机制参考前文「安全与信任边界机制图」。

3. 核心流程图

路线图中的代表链路是:

permissions / sandbox / MCP / bridge / managed settings

下图按颜色区分边界:蓝色是模型到工具主链,红色是权限/拒绝边界,绿色是路径与 sandbox,紫色是外部连接,橙色是管理策略。

这部分机制参考前文「安全与信任边界机制图」。

4. 关键源码入口

职责文件
工具接口与 ToolUseContextsrc/Tool.ts
工具池组装与 deny 过滤src/tools.ts
工具执行控制链src/services/tools/toolExecution.ts
权限规则和模式src/utils/permissions/permissions.ts
权限结果类型src/utils/permissions/PermissionResult.ts
权限规则解析src/utils/permissions/PermissionRule.tssrc/utils/permissions/permissionRuleParser.ts
文件路径权限src/utils/permissions/pathValidation.tssrc/utils/permissions/filesystem.ts
sandbox adaptersrc/utils/sandbox/sandbox-adapter.ts
Bash sandbox 判定src/tools/BashTool/shouldUseSandbox.ts
Bash 权限细分src/tools/BashTool/bashPermissions.ts
权限 UI / React 决策src/hooks/useCanUseTool.tsxsrc/components/permissions/PermissionRequest.tsx
PermissionRequest structured IOsrc/cli/structuredIO.ts
MCP config / approval / authsrc/services/mcp/config.tssrc/services/mcpServerApproval.tsxsrc/services/mcp/auth.ts
bridge 启动与 remote control gatesrc/bridge/initReplBridge.ts
bridge permission callbackssrc/bridge/bridgePermissionCallbacks.ts
session ingress authsrc/utils/sessionIngressAuth.ts
managed settingssrc/utils/settings/settings.ts
plugin-only policysrc/utils/settings/pluginOnlyPolicy.ts
workspace trustsrc/components/TrustDialog/TrustDialog.tsx
hook trust / managed-only snapshotsrc/utils/hooks.tssrc/utils/hooks/hooksConfigSnapshot.ts

4.1 主线与场景特殊处理分类

机制/模块分类为什么这样归类
assembleToolPool() / filterToolsByDenyRules()安全/治理横切在模型看到工具前收缩工具面,减少误调用可能
schema / validateInput()主线机制 + 安全横切工具执行前的结构和业务参数校验,防止无效输入进入副作用点
runPreToolUseHooks()安全/治理横切工具执行前的外部策略插入点,可 deny/ask/updateInput/add context
hasPermissionsToUseTool()安全/治理横切权限决策核心,合并规则、工具专属权限、mode、auto/headless 行为
deny-first 规则安全/治理横切deny 优先于 ask/allow/bypass,是权限系统的底线之一
auto mode classifier场景增强 + 安全横切只在 feature 和 auto/plan-auto 模式下触发;部分 safetyCheck 不可被 classifier 取代
trusted settings source安全/治理横切高风险 opt-in 排除 projectSettings,防止恶意项目自我提权
path validation安全/治理横切解析真实路径、glob base、tilde、UNC/path traversal、工作区和 sandbox allowlist
sandbox write allowlist场景增强 + 安全横切sandbox 开启时把允许写目录并入路径权限,但仍尊重 denyWithinAllow
MCP approval场景增强 + 安全横切只在 MCP server / tool 存在时触发,负责外部工具来源治理
bridge remote control gate场景增强 + 安全横切只在 bridge enabled、OAuth 可用、组织策略允许时启动
session ingress auth场景增强 + 安全横切remote / bridge 通道的认证头构造与 token 更新
workspace trust安全/治理横切对项目 hook、allowed tools 等可执行扩展面做信任确认
managed hooks / plugin-only policy安全/治理横切组织策略可限制 hook/customization 来源
telemetry / transcript可观测/恢复支撑不直接阻止风险,但提供决策来源、错误、审计和复盘基础

5. 机制拆解

5.1 安全不是只靠“权限弹窗”

工具调用主链在第 3 期已展开。安全复盘时要强调:权限 UI 只是 ask 分支的一部分。真正的边界包括:

  1. 工具是否被放进模型可见 tool pool。
  2. 工具输入是否通过 schema 和 validateInput。
  3. PreToolUse Hook 是否阻断或改写。
  4. 权限规则是否 deny / ask / allow。
  5. 工具自己的 checkPermissions() 是否要求内容级确认。
  6. 当前 mode 是否允许 auto / bypass / dontAsk。
  7. UI、SDK、bridge、headless Hook 是否能给出最终决策。

因此不能把安全性等同于“用户点了一次允许”。

5.2 deny 优先,auto/bypass 不是无条件通行

permissions.ts 的权限流程先处理 deny、ask、工具专属 check、requiresUserInteraction、content ask 和 safetyCheck,再进入 bypass / allow / mode 逻辑。

auto mode 分支还有额外边界:

  • 非 classifier-approvable safetyCheck 不能被 acceptEdits fast-path、safe-tool allowlist 或 classifier 自动批准。
  • PowerShell 在 POWERSHELL_AUTO_MODE 未开启时要求显式用户权限。
  • Agent 和 REPL 被排除在 acceptEdits fast-path 之外,因为它们可能包含更复杂的内层工具或 VM 逃逸风险。
  • classifier 出错会记录 error dump,不能默默当成 allow。

这些源码分支说明 auto mode 是“受限自动审批”,不是 YOLO 式绕过。

5.3 projectSettings 被排除在高风险 opt-in 之外

settings.ts 中多个函数显式排除 projectSettings:

  • hasSkipDangerousModePermissionPrompt():projectSettings 不能接受 bypass permissions mode dialog。
  • hasAutoModeOptIn():projectSettings 不能接受 auto mode opt-in。
  • getUseAutoModeDuringPlan():projectSettings 不能控制 plan mode 是否使用 auto semantics。
  • getAutoModeConfig():projectSettings 不能注入 classifier allow/deny/environment 规则。

注释给出的原因很明确:恶意项目不应通过本地项目设置自我提权或注入 classifier 规则。这是 workspace trust 之外的另一层配置来源边界。

5.4 path validation 把“字符串路径”转成安全判断对象

pathValidation.ts 处理 glob base、tilde expansion、resolved path、UNC/path traversal、sandbox allowlist 等问题。

isPathInSandboxWriteAllowlist() 只有在 SandboxManager.isSandboxingEnabled() 时返回 true。即使路径在 sandbox allowOnly 中,也会先检查 denyWithinAllow,例如某些配置文件仍可被拒绝。这说明 sandbox allowlist 不是绝对覆盖 deny 规则。

isPathAllowed() 会按 operation type 区分 read/edit,并先检查 deny rules。路径权限不是简单字符串前缀匹配,而是结合 realpath/symlink 解析和工作路径判断。

5.5 sandbox 是权限系统的增强,不是所有 Bash 的默认执行模型

Bash 工具还有自己的权限和 sandbox 判断文件,例如 BashTool/bashPermissions.tsBashTool/shouldUseSandbox.ts。sandbox 可让某些命令在受限环境中更安全地运行,也可影响 auto allow。但第 3 期已确认 sandbox auto allow 只对 Bash、sandbox 开启且命令适合 sandbox 时生效。

因此,研究中不能写“所有 shell 都在 sandbox 里执行”。正确表述是:sandbox 是按配置、平台、命令形态和工具判断介入的安全增强。

5.6 MCP 是外部工具边界,需要配置、审批和权限规则共同治理

MCP 工具进入 tool pool 前会经过 MCP client 状态、server tool 可用性、配置和 deny filtering。agent 选择也会检查 required MCP servers 是否真的有 tools available,连接但未认证的 server 不算可用。

services/mcpServerApproval.tsx 会为 pending project servers 展示 approval dialogs。settings permission validation 中 MCP rules 支持 server-level、tool-level 和 wildcard,但不允许带括号 pattern,这避免把非 MCP 的内容匹配语义错误套到 MCP server/tool 名称上。

MCP 的风险不是“本地工具风险”的重复,而是外部 server / channel / auth / elicitation 的组合边界。

5.7 bridge / remote control 必须过 runtime、OAuth 和组织策略

bridge/initReplBridge.ts 的启动顺序很明确:

  1. isBridgeEnabledBlocking() runtime gate。
  2. getBridgeAccessToken(),没有 Claude.ai OAuth token 则失败并提示 /login
  3. waitForPolicyLimitsToLoad() 后检查 isPolicyAllowed('allow_remote_control')
  4. 对过期且刷新失败的 OAuth token 做 skip 和跨进程 backoff,避免 401 无限循环。

bridge 不是本地默认能力,而是受账号、组织策略和 token 状态控制的 remote-control 通道。structuredIO.ts 还处理 bridge control_response / control_cancel_request 与 SDK permission prompt 的竞争,避免 stale prompt 悬挂。

5.8 workspace trust 与 Hook trust 保护可执行扩展面

第 5 期已经确认 Hook 可以执行 command/prompt/http/agent/function 等 handler。utils/hooks.ts 在交互模式下要求 workspace trust;hooksConfigSnapshot.ts 处理 disableAllHooks、allowManagedHooksOnly 等 managed-only 策略。

TrustDialog.tsx 还会检查项目/本地 settings 或插件 command 中是否有 allowedTools 等风险内容,并询问用户是否信任当前 folder。它保护的是“项目配置可影响模型和工具行为”的边界。

5.9 多 agent 扩大风险面,靠权限冒泡和隔离收缩

第 7 期确认:

  • Agent 类型受 deny rule 控制。
  • fork agent 使用 permissionMode: 'bubble'
  • worktree isolation 可隔离文件副作用。
  • in-process teammate 不能 spawn background agents。
  • remote agent 要先过 eligibility 和 remote session 注册。

多 agent 的安全重点不是禁止拆分,而是让拆分后的子执行仍可见、可中断、可恢复,并把权限请求带回父会话或宿主。

6. 对稳定解决问题能力的贡献

6.1 降低模型幻觉造成真实副作用的概率

工具可见性、schema、validateInput、permission、sandbox 和 Hook 分层拦截,把“模型想做”变成“经过验证后才能做”。

6.2 防止项目配置自我提权

高风险 opt-in 排除 projectSettings,workspace trust 保护项目 hooks / allowedTools,managed settings 可以限制非 managed hooks。这些都针对“打开陌生仓库即被配置劫持”的风险。

6.3 让无交互场景仍有明确拒绝路径

headless / async / bridge 场景无法弹 UI 时,权限系统会尝试 PermissionRequest Hook 或宿主回调;没有可用决策时应 deny,而不是默认 allow。

6.4 外部连接有独立信任边界

MCP、bridge、remote agent、session ingress 都不是普通本地函数调用。源码为它们设置 auth、approval、policy、channel 和恢复逻辑。

6.5 安全事件可审计

权限来源、auto mode decision、API errors、bridge skips、hook events、tool result 和 transcript 都会进入日志/telemetry/session storage,为复盘提供证据。

7. 风险、边界与待验证问题

风险/边界影响防御性解读
权限路径高度分支化新增工具或 mode 容易漏接 deny/ask 语义应优先复用 checkPermissionsAndCallTool()hasPermissionsToUseTool()
auto classifier 依赖模型判断分类错误可能误判风险源码通过 safetyCheck 免疫、PowerShell guard、Agent/REPL fast-path 排除、denial tracking 降低风险
sandbox 条件化误以为所有 Bash 都被隔离会低估风险文档和 UI 应持续区分 sandboxed allow 与普通 permission allow
MCP server 是外部信任域server 工具描述、auth、elicitation、channel 都可能影响行为MCP approval、rule validation、server/tool filtering 是必要但不等于完整供应链审计
bridge/remote control 依赖账号与策略OAuth/组织策略/网络状态变化会改变能力bridge 启动 gate 和 token backoff 避免默认开放和认证死循环

8. 下一期衔接

第 9 期进入“可观测性、审计与持久化”。安全边界只有在可复盘时才真正可治理。下一期将分析 transcript JSONL、parentUuid chain、content replacement、session restore、task sidecar、progress state、analytics、OTel 和 debug logs 如何支撑恢复、审计和调试。

机制主线收束

站在架构师视角,我会把这组源码机制收束为三个问题:为什么需要它,什么时候必须引入它,以及真正要设计的是什么。

  • why:安全边界解决的是模型错误、恶意项目配置、外部连接和多 agent 放大真实副作用的问题。
  • when:只要 agent 接触文件系统、shell、MCP、remote、hooks、项目配置,就必须做分层安全。
  • what:配置源可信、工具可见、输入合法、权限通过、路径安全、外部连接可审批、执行可审计,副作用才应该发生。

安全与信任边界这组源码最值得带走的,不是某个函数或某个配置项,而是它如何把模型能力放进一组可验证、可拒绝、可恢复、可审计的工程边界里。读源码时,如果只记住名词,会很快散;如果抓住 why、when、what,就能把这组机制迁移到自己的 agent 架构判断中。