ARTICLE · 1318762
一把我以为删掉的密钥,被 AI 工具复制了 17 份
QUOTE
把 key 放进 .env,早就不算安全实践,只是把风险挪了个文件夹。
—— 3182 个文件的盘点账

10 月 24 日,晚上十点半。我在改一个排行榜接口,手机弹出某云厂商的邮件:「检测到您的 API Key 在公开渠道出现」。
心脏骤停两秒。点进去一看,是扫到了我两年前传的一份教程示例仓库,里面那把 key 早在 2 月就吊销了。虚惊一场。
但虚惊之后我睡不着了。10 月接连出了好几起密钥相关的事件——Railway 泄了部分客户的环境变量,LiteLLM 的投毒版本专门搜刮 AI 厂商的 key。这些我都只是看的公开报道,细节以官方报告为准,但有一件事不用等报告:我的开发机上跑着三个 AI 编程工具、七八个 MCP server,它们读文件、跑命令、写日志——我的 key 到底散在这台机器的哪些地方?
我原来以为答案很简单:.env,加上工具自己的配置文件。第二天我请了半天假,把开发机翻了一遍。结论让我后背发凉:47 个目录、3182 个文件里,藏着 17 处明文密钥,对应 6 把不同的真 key。其中一把,我以为它 2 月就死了。

— 17 处明文密钥的 6 类藏身处;橙色是这篇的主角
本文看点
01
17 处密钥的 6 类藏身处
02
一把「死」了 8 个月的 key
03
我为啥弃用了全盘扫描
01
THE SHALLOW END
最浅的一层:配置文件里的 5 份
先说最容易想到的地方。我的 MCP 配置里躺着 5 份明文:两份在项目的 .mcp.json(一个数据库连接串和一张地图服务的 key),三份在用户目录的工具配置里。
这不是我手滑——装 MCP server 的时候,README 就是教你把 key 直接粘进 JSON 的,我照做了,一照做了两年。照着官方文档装工具,本身就会制造密钥副本。
后来我去查了个数:GitGuardian 统计过,2025 年公开的 GitHub 上,MCP 配置文件里躺着 24008 个独一无二的明文密钥,其中 2117 个至今仍然有效。我不孤独,我只是大多数。
这 5 份我全改成了环境变量引用,花 40 分钟。
02
DEEPER DOWN
稍深的一层:历史和会话里的 7 份
再往下翻,事情开始不对劲了。
shell 历史里 4 份
都是 export XXX_API_KEY=sk-xxx 这种命令,最早一条是去年 3 月的。我从来没意识到,每次在终端手动 export 一把 key,它就被永久抄送进 .bash_history——还会跟着 dotfiles 仓库同步到我另外两台机器。
AI 工具的会话文件里 3 份
这个最意外。有个工具会把会话期间的环境变量抓进项目目录下的状态文件,我 2 月在终端 export 过一把测试 key,被它抓走了,就躺在那个我从来没打开过的 json 里。要不是这次盘点,它会一直躺下去。
这 7 份的处理麻烦一些:历史文件清掉对应行,状态文件直接删,两台同步机器各清一遍,1 小时。
顺带说一句,这两类位置都没有任何工具提醒过我。pre-commit hook 只盯着 git,而 AI 工具从来不走 git。
03
THE UNDEAD KEY
最深的一层:一把死了 8 个月的 key
真正让我后背发凉的,在最深处。
一个云厂商工具的目录里,躺着一份 .bak——某次改配置时自动生成的备份文件,里面明文写着一把 key。我盯着它看了十秒钟,因为这把 key 我 2 月就吊销了。我以为。

— 扫描命中现场:这份 .bak 躺在工具目录里,从没被任何流程碰过
登录厂商后台查调用记录:最后一次调用是 1 月 28 日。也就是说,这把 key 从 2 月起就以「已吊销」的状态在我的硬盘上活着,活了 8 个月。万幸它是真被吊销了,硬盘上这份只是一具尸体。但那个瞬间我想明白一件事:
「我以为「吊销了」的东西,和我实际验证过「死了」的东西,中间隔着一整个硬盘。」
顺带一提,废弃项目里还翻出 1 份 .env,是去年 11 月烂尾的一个 side project。加起来正好 17 份。
账单没爆不是你安全,多半是你运气好。我的运气在 10 月 24 日用掉了一次,我不想再赌第二次。
04
THE 91% NOISE
我弃用了全盘扫描
处理完之后我想了个一劳永逸的办法:拿 gitleaks 全盘扫一遍,以后每周扫一次。
结果它给我吐了 3900 多行输出——测试 fixture、示例文档、我自己写的假 key,91% 是噪音,人工核了四十分钟核到眼瞎,第二周再跑又多出一堆新噪音。
第三周我把全盘扫描弃用了。改成笨办法:自己写了个 80 行的脚本,只扫 6 类白名单路径(MCP 配置、shell 历史、AI 工具状态目录、日志目录、.env、.bak 备份),10 秒跑完,输出不超过 20 行,每一行都值得看。
MISTAKE · 弃用判断
安全工具的产出如果九成是噪音,它就不是在帮你,是在训练你忽略警报。全盘扫描这个思路对仓库是对的,对整台机器是错的——机器上大部分「命中」本来就不是风险,真正会咬人的只有那 6 类路径。
05
THE RULES
三条规矩,和 3.5 小时的账
盘点加清理,总共花了 3.5 小时。6 把 key 全部轮换,每把设了月消费上限——对齐历史月均的 2 倍。钱一分没花,纯时间。
改了 11 处配置,另外 6 份副本直接删了。之后我给自己立了三条规矩:

— 每把 key 的处置闭环:吊销不是终点,验证才是
key 只活在环境变量里。任何配置文件只允许出现变量引用;装新 MCP server 时 README 让粘 key,我粘引用。
每把 key 必须有消费上限和独立的用量面板。账单异常要能在当天定位到具体哪把 key,不做合并大账。
每个季度跑一次那个 80 行的脚本。吊销 key 之后必须验证——查调用记录,确认它真死了。

— 三条规矩贴在工位上,比任何安全工具都管用
∞
THE TAKEAWAY
写在最后
最后说个可能会被反驳的判断:在 AI 工具遍地读写文件的今天,把 key 放进 .env 已经算不上安全实践,它只是把风险从一个文件夹挪到了另一个文件夹。真正的分界线不是文件藏得好不好,而是这把 key 泄了之后,你多久能知道、多快能掐断。
这个判断的边界我也说清楚:我的样本只有一台开发机、3 年的使用痕迹、17 处命中,而且我是单兵作战,没有团队级的密钥管理平台。如果你在管一个团队的机器,结论大概率更难看。
你的机器上跑着几个 AI 工具?那 6 类位置,你敢说你全翻过吗?评论区聊聊你查到的最意外藏身处,我挑几个典型的整理成一篇续篇。















































































