Skip to content
源码分析手册

Undercover 模式:Anthropic 员工的“防泄密”护盾

一句话讲清楚

Undercover(潜伏)模式是 Claude Code 为 Anthropic 内部员工设计的一种安全机制。当员工在公共仓库(Public Repo)中使用 Claude Code 时,该模式会自动激活。它会严厉限制模型在生成的 Commit Message 或 PR 描述中包含任何 Anthropic 内部代号(如 Capybara, Tengu)、内部 Slack 频道或未公开的模型版本号。

实现细节

这不是一个简单的标志位,而是一套深植于代码中的自动化防线:

  1. 自动识别与触发:系统维护了一个包含约 75 个内部仓库的允许列表(INTERNAL_MODEL_REPOS),其中包括 anthropics/anthropicclaude-cli-internal
    • 触发逻辑:当检测到当前 Git 远程仓库不在列表中时,自动激活 Undercover 模式。
    • 安全默认值:如果无法确定(例如在没有 Git 的临时目录下运行),则默认开启潜伏模式,以宁可错杀、绝不泄密的姿态运行。
  2. 严厉的指令注入:一旦激活,getUndercoverInstructions 会向系统提示词(System Prompt)中注入一段“CRITICAL”级别的指令。
    • 禁止项:严禁提及动物代号(Capybara, Tengu)、具体版本号(Opus 4.7)、Go 链接、内部仓库名。
    • 伪装要求:甚至禁止模型自称 AI,要求它像一个普通的“人类开发者”一样写提交信息。
  3. 身份剥离(Attribution Stripping):在 Undercover 模式下,Claude Code 会强制移除所有可能暴露其 AI 身份的 Git 尾注(Trailers),如 Co-Authored-By 归属信息。
  4. 死代码消除(Dead-Code Elimination)
    • 源码中所有关于潜伏模式的逻辑都被包裹在 process.env.USER_TYPE === 'ant' 的条件分支中。
    • 外部版本透明:由于 USER_TYPE 是构建时的常量,打包工具(Bundler)在生成面向普通用户的版本时,会直接通过 Tree-shaking 彻底剔除这些代码路径。你拿到的 Claude Code 里甚至不存在这段逻辑,这既保护了代码整洁,也避免了外部用户窥探内部仓库列表。
  5. 强制性与不可逆性:源码明确注释:“There is NO force-OFF switch”(没有强制关闭开关)。只要自动化检测没过,员工就必须在潜伏模式下工作。

实战注意事项

  • 单向透明:这套机制的存在揭示了一个事实:Anthropic 的工程师们已经在大规模使用 Claude Code 开发他们的所有项目,包括那些面向公众的开源项目,但他们对安全性有着极高的警惕。
  • 强制覆盖:即使在内部仓库,员工也可以通过环境变量 CLAUDE_CODE_UNDERCOVER=1 强制开启此模式,作为双重保险。
  • 外部用户的隐身:对普通开源用户来说,你永远不会看到这个模式的对话框或提示词注入,因为它在编译阶段就已经消失了。

延伸阅读

  • 去翻翻 src/utils/commitAttribution.ts,那里藏着那 75 个神秘的内部仓库名单(尽管很多你可能没听说过)。
  • 如果你对 Git 提交信息的归属统计感兴趣,可以研究 calculateCommitAttribution

源码锚点

  • src/utils/undercover.ts:控制潜伏模式的核心开关和指令注入内容。
📄 src/utils/undercover.ts — 控制潜伏模式的核心开关和指令注入内容。L28-37 of 90
typescript
export function isUndercover(): boolean {
  if (process.env.USER_TYPE === 'ant') {
    if (isEnvTruthy(process.env.CLAUDE_CODE_UNDERCOVER)) return true
    // Auto: active unless we've positively confirmed we're in an allowlisted
    // internal repo. 'external', 'none', and null (check not yet run) all
    // resolve to ON. The check is primed in setup.ts; only 'internal' → OFF.
    return getRepoClassCached() !== 'internal'
  }
  return false
}
  • src/utils/commitAttribution.ts:定义了内部仓库白名单 INTERNAL_MODEL_REPOS
📄 src/utils/commitAttribution.ts — 定义了内部仓库白名单 `INTERNAL_MODEL_REPOS`。L30-59 of 962
typescript
const INTERNAL_MODEL_REPOS = [
  'github.com:anthropics/claude-cli-internal',
  'github.com/anthropics/claude-cli-internal',
  'github.com:anthropics/anthropic',
  'github.com/anthropics/anthropic',
  'github.com:anthropics/apps',
  'github.com/anthropics/apps',
  'github.com:anthropics/casino',
  'github.com/anthropics/casino',
  'github.com:anthropics/dbt',
  'github.com/anthropics/dbt',
  'github.com:anthropics/dotfiles',
  'github.com/anthropics/dotfiles',
  'github.com:anthropics/terraform-config',
  'github.com/anthropics/terraform-config',
  'github.com:anthropics/hex-export',
  'github.com/anthropics/hex-export',
  'github.com:anthropics/feedback-v2',
  'github.com/anthropics/feedback-v2',
  'github.com:anthropics/labs',
  'github.com/anthropics/labs',
  'github.com:anthropics/argo-rollouts',
  'github.com/anthropics/argo-rollouts',
  'github.com:anthropics/starling-configs',
  'github.com/anthropics/starling-configs',
  'github.com:anthropics/ts-tools',
  'github.com/anthropics/ts-tools',
  'github.com:anthropics/ts-capsules',
  'github.com/anthropics/ts-capsules',
  'github.com:anthropics/feldspar-testing',

基于 Claude Code v2.1.88 开源快照的深度分析