TeamAI 模型配置下发安全:apply_model_config 如何完整保护 API 密钥
【免费下载链接】teamai-cliMake Every Team AI Native项目地址: https://gitcode.com/GitHub_Trending/te/teamai-cli
TeamAI是一款让团队 AI 原生的命令行工具(Make Every Team AI Native)。当企业后端通过模型配置下发推送apply_model_config任务时,任务里携带的API 密钥(代理网关 Token)会落到你的本地配置文件。密钥一旦泄露就是资损,TeamAI 为此设计了五层纵深防御,确保密钥只在落盘、校验、隔离、防冲突、防回传等每个环节都被严格保护 🛡️
背景:模型配置下发的工作流程
TeamAI 的本地代理会定期与后端同步。后端可以在同步响应中下发一条apply_model_config任务,cmd字段是一段 JSON,描述一个模型候选集,包含provider、model_id、base_url以及敏感的api_key。
客户端收到后会校验 payload,把模型配置写入对应 Agent(CodeBuddy、WorkBuddy 或 Claude)的本地文件,再向服务端回执成功或失败。完整协议说明见 docs/usage-guide.zh-CN.md。
关键实现集中在 src/local-agent.ts 的applyModelConfig函数中。
第一层:严格的载荷校验,拒绝一切"脏输入"
下发内容是不可信的远程数据,解析入口 parseDeliveredModels 做了多重"安检":
- 必填字段强校验:
provider、model_id、name、base_url、api_key必须是非空字符串,见 requireModelString,任何一项缺失都直接抛错并回执失败; - URL 协议白名单:
base_url必须是合法的 http/https 地址,防止被塞入file://、javascript:等危险协议; - 原型污染防护:
model_id为__proto__、prototype、constructor时直接拒绝(第 2184 行); - 去重与类型约束:重复的
model_id、非法的max_tokens数值都会被拦截。
任何一条不合规,任务立即失败,一个字节都不会写入磁盘。
第二层:文件权限 0600 + 原子写入,密钥"藏"在只有属主能读的角落
真正落盘的是 writeModelJson,两个细节值得新手理解:
- 权限模式
0600:写入的临时文件在原子 rename 之前就被设为"仅属主可读写"。注释里写得很明白——如果在 rename 之后再 chmod,中间会存在一个"符号链接跟踪的时间竞争窗口"(TOCTOU),先设权限再替换才能彻底堵住。 - 符号链接保留:如果你的配置文件是指向别处的符号链接,TeamAI 会解析到真实路径写入,绝不替换你管理的链接。
同样的 0600 权限策略也用于登录凭证文件,见 writeTokenFile。
第三层:Gitignore 自动隔离,防止密钥被 commit 出去
workspace 级的模型配置会写入<workspace>/.codebuddy/models.json,这个文件含凭证。TeamAI 会自动在 ensureWorkspaceModelGitignore 中创建或更新.codebuddy/.gitignore,把models.json排除在版本控制之外。
另外,workspace 级下发只在目标路径已注册在 reporter 的 workspace bindings 中时才被接受,未注册的路径一律拒绝——后端无法把配置"种"到任意目录。
第四层:用户配置优先,冲突时"让路"并留痕
这是最容易翻车的地方:Agent 的配置文件是用户自己维护的。TeamAI 的做法:
- 哈希所有权登记:每次托管写入后,把内容哈希记入 manifest(
entryHash)。下次同步时,只有哈希匹配的条目才被视为"TeamAI 管理的",用户自己添加的模型条目原样保留,即使 model_id 相同; - 双通道冲突检测(针对 Claude 网关):不仅检查
~/.claude/settings.json的env,还检查进程 shell 环境变量(第 2424-L2446 行)。如果你用 shellexport ANTHROPIC_*配了自己的网关,TeamAI 会跳过写入,并把跳过的 key 记录到~/.teamai/reporter/errors.jsonl留痕; - 受保护 key 清单:
ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_API_KEY等十余个敏感环境变量都在保护范围内; - 不误伤其他 Agent:不支持的 Agent 直接回执失败,绝不会写错配置文件。
第五层:API 密钥永不回传——只留在本地磁盘
上报方向同样安全。模型清单回传时(buildModelReport 相关逻辑)只包含provider、model_id、name和source: "enterprise",api_key字段永远不会出现在上报载荷中。官方文档的原话是:"api_key 不会被回传——ProxyToken 只留在本地磁盘"。
再加上 src/utils/redact.ts 提供的全局脱敏能力(对 PEM 私钥、JWT、sk-前缀 token、Bearer头、连接串密码等做正则遮罩),即使日志意外捕获了密钥形态的文本,也会被替换为<REDACTED:***>占位符。
安全机制速览
| 防护层 | 机制 | 对应代码位置 |
|---|---|---|
| 输入校验 | 必填字段 / URL 白名单 / 原型污染拦截 | parseDeliveredModels |
| 磁盘权限 | 0600 + 先设权限后原子替换 | writeModelJson |
| 版本控制隔离 | 自动写入.gitignore | ensureWorkspaceModelGitignore |
| 用户配置保护 | 哈希登记 + shell env 冲突检测 | reconcileClaudeModels |
| 密钥不回传 | 上报载荷剥离api_key+ 日志脱敏 | redact.ts |
相关行为均有完整测试覆盖,见 src/__tests__/local-agent-model-config.test.ts,包括"用户 shell 冲突时跳过网关写入"等回归场景。
写在最后
对普通用户来说,你不需要理解每一行实现——只要知道:密钥校验后才落盘、文件只有你能读、永远不会进 git、永远不会回传服务端,你自己的配置永远不会被覆盖。这正是企业级"模型配置下发"与"随手写个配置文件"的本质区别。如果想动手体验,clone 仓库后运行本地测试套件即可复现上述所有保护行为:
git clone https://gitcode.com/GitHub_Trending/te/teamai-cli更多端点协议与回执细节,欢迎阅读 docs/usage-guide.md 原文。
【免费下载链接】teamai-cliMake Every Team AI Native项目地址: https://gitcode.com/GitHub_Trending/te/teamai-cli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考