API Key 泄露

承载调用权限的密钥脱离了它本该存在的唯一位置(服务端环境变量),散落到代码、文档、测试桩与 AI 记忆里;对 vibe coding 的非技术使用者来说,这不是安全事故,而是开发卫生问题。

简介

API Key 泄露指的是:一个云服务凭证(DeepSeek、OpenAI、Anthropic、各类 SaaS 的 key/token)被写入本不该出现的位置,从而产生多个可被读取、复制、外流的副本。它和传统意义上的「被黑客攻破」不同——绝大多数泄露不需要任何攻击技巧,只需要密钥曾经在某个文件里存在过一次,而这个文件后来被提交、被分享、被同步、或被 AI 记住。

它在非技术背景的 vibe coding 场景里尤其高发,原因很结构性:AI 的目标函数是「让服务跑起来」,而「密钥不要到处放」是一条它从未被告知、也不影响跑通的约束。作者张亮-leo 的复盘把这一点说得非常清楚——AI 写 fallback 是为了保证环境变量缺失时不报错,写部署文档是为了让命令能照抄执行,写测试报告是为了记录「用的是哪把 Key」。每一步都是称职完成指令,只是没人告诉它这个东西不能复制 22 份。

对个人开发者而言,泄露的代价通常不表现为数据被窃,而表现为账户被薅:盗用方会用你的额度跑自己的调用。因为调用是「合法凭证发起的合法请求」,服务商侧看起来和正常用量没有区别,所以它极难在事前拦截,只能靠账单与限额在事后止损。

关键信息

  • 高发位置(7 类藏法):代码里的 fallback(process.env.KEY || 'sk-…',源码一份、编译产物又一份);各类 .env(开发/生产/服务端各一份);.env.example(本应是格式样例,却放了真值);部署脚本与 docker-compose(可为单一脚本 3 处明文);测试文件里的测试桩;文档(修复报告、部署总结、测试计划、手动部署指南);以及 AI 工具的项目记忆——把 Key 当作「需要记住的信息」长期留存。
  • 仓库级放大器:没有 .gitignore 的仓库、以及只忽略 .env 而漏掉 .env.production / .env.*.gitignore,会把本地文件问题直接升级为公开泄露。
  • 损耗量级参照:本文案例中,¥80.58 在 DeepSeek 上对应 1,752 次请求、1.07 亿 token;这也是判断「用量是否异常」的量级标尺——低价模型的异常账单往往先表现为请求数,而不是金额。
  • 发现窗口往往被业务噪音掩盖:案例中内测期的自然增长、邀测开放后的用户变多、以及平台涨价,三者叠加使一个月的异常消耗看起来像正常波动。真正暴露问题的是「邀测结束后按道理不该有消耗」这个反事实判断。
  • 溯源经常做不到:当同一把 Key 存在 22 个位置时,泄露路径无法回溯(承载服务器甚至早已注销)。因此处置逻辑必须是「止损优先于溯源」。
  • 吊销顺序错误会放大损失:案例作者先排查未撤销,导致「上午烧了 7 块,下午排查继续烧了 2 块」。

核心特性

1. 泄露是「多副本问题」,不是「单点被攻破问题」

传统安全模型关心「这一处会不会被攻破」,而 API Key 泄露的实际形态是:密钥在不同载体上产生了 22 个可读副本,攻击面等于副本数的并集。这意味着加固任何一个位置都无意义——只要还有第二个副本存在,第一个副本守得多严都不改变结果。防御的最小单位因此从「保护文件」变成「让密钥只存在一处」。

2. AI 是复制的加速器,而不是判断者

在 22 个副本的形成过程中,AI 的角色是高效执行:它按需把密钥写进 fallback、脚本、文档、测试桩和长期记忆,每一处都有正当的局部理由。AI 不会主动评估「这个位置是否属于授权载体」,所以在缺少显式约束时,它会持续扩大副本集。反向推论:约束必须显式写进工作流(例如「Key 只放环境变量,代码里不留 fallback」),否则默认行为就是扩散。

3. 事前拦截弱、事后止损强

因为盗用方使用的是合法凭证,从服务商侧看请求是「正常的」。可以在事前生效的只有两条低成本手段:消费限额(被盗时限额就是止损线)与凭证生命周期管理(服务/项目下线时顺手作废它用过的 Key)。其余防线(扫描、审计、监控)都属于事后。

4. 它是「卫生问题」,因此靠习惯而非靠技术解决

作者明确拒绝把它定性为事故:「说白了,这就是开发过程中的卫生问题。」这个定性的实践含义是——解决方式不是引入更复杂的密钥管理设施,而是把几条稳定的习惯嵌进日常动作:新建仓库先写 .gitignore.env.example 只放占位符、下线时作废 Key、发现异常先吊销后排查。

不同素材中的观点

  • 2026-09-24-woshipm-vibe-coding-api-key-leak-80-yuan|非技术背景的 vibe coder(张亮-leo,人人都是产品经理):泄露的根本原因不是恶意,而是「没人告诉 AI 这个东西不能到处放,连我自己当时也没这个意识」。核心结论是归因要放在工作流上而不是模型上——「它每一步都没做错,都是在认真完成我交代的任务」。给出的处置顺序是止损优先:发现异常先把 Key 撤销掉,然后才是排查;并且强调「API Key 只放在环境变量里,代码里不留 fallback——报错好,能报错,比悄悄用上一把真 Key、然后被别人拿去薅要好 1000 倍」。同篇评论区(「别叫我静姐」)补充了另一层成因:主流 AI coding 工具基本都有敏感信息拦截提醒,作者全程未触发,说明问题不只是工具缺护栏,而是使用者把「先跑通」的优先级放到压过了既有的安全基线——做运营出身对线上服务的安全基线其实有感知,是 vibe coding 时把安全习惯直接丢了

(当前仅一篇素材,后续素材的同类观点将追加于此。)

实用信息

防护清单(可直接执行)

  1. 一个项目一把 Key,命名写完整:「项目名-环境-云服务商」,出问题看名字就知道去哪找。
  2. Key 只放环境变量,代码里不留 fallback
  3. 新建仓库第一件事是写 .gitignore,忽略所有 .env*(不只是 .env)。
  4. .env.example 只放占位符,不放真值。
  5. 不把 Key 贴进任何对话框——AI 会记住,并写进它的笔记与文档。
  6. 设消费限额,作为被盗用时的止损线。
  7. 项目或服务器下线时,顺手作废它用过的 Key
  8. 发现异常,先撤销 Key,再排查

排查流程(事后定位)

  1. 看云服务后台用量:确认「按道理不该有消耗的时间段」是否仍在产生费用。
  2. 按创建时间与近 30 天调用曲线定位是哪一把 Key(找出与已知业务不匹配的那条曲线)。
  3. 从部署平台逐项核对各项目环境变量。
  4. 仍定位不到时做本机全盘扫描:遍历项目目录按 Key 字符串全文搜索,把命中文件按 7 类藏法分类。

适用场景与边界

  • 适用:个人开发者、非技术背景的产品/运营在 vibe coding 中调用任何按量计费的云 API。
  • 不适用/不充分:把上述清单当作企业级密钥管理方案。它是个人卫生底线,不覆盖轮换策略、最小权限、审计留痕、多人协作中的密钥分发。
  • 相邻但不同的概念:密钥轮换(rotation)、最小权限(least privilege)、Secret Manager 属于工程化方案;本文讨论的是这些方案落地之前,个人工作流里必须有的最低防线。