密钥扫描与轮换智能体。
「找出泄漏的凭据」是早已解决的那一半,而你很可能正在为它重复付费;真正要你命的那一半是:你已经找到的那些,还在正常工作。GitGuardian 2026 年的报告把它在 2022 年确认为有效的凭据重新测了一遍,发现四年之后仍有超过 64% 依然有效——与此同时,仅 2025 年就有 2,900 万个新的硬编码密钥被推到了公开的 GitHub。所以这个智能体的交付物不是一张发现清单,也不是一个删掉某一行的拉取请求——而是一份你能证明已经死掉的凭据,连同一张回执。请从这一点倒推整套设计,而起点是这个事实:证明一份凭据已死,必须去使用它,而那正是这个智能体绝不可以拥有的那一项能力。
先把指标定下来,因为那个显而易见的指标奖励的是错的活。
扫描器便宜、准得够用,而且早就在跑着了:GitHub 的推送保护、你 CI 里的扫描器,以及你安全团队买的那个商业检测器,找出来的基本是同一批高熵字符串。在这个技术栈前面再加一个智能体,产出的是更多发现,而更多发现不是目标。数字说明了失败住在哪里:
- 2025 年在公开 GitHub 提交里检出的新硬编码密钥是 2,900 万个——同比上升 34%,是有记录以来单年涨幅最大的一次。瓶颈不是数量;没人缺发现。
- 2022 年被确认为有效的凭据里,在 2026 年 1 月重新测试时仍有超过 64%依然有效。四年。这不是一个检测缺口,这是一个撤销缺口,而它就是全部问题。
- 32.2% 的内部仓库里至少有一个硬编码密钥,而公开仓库是 5.6%——这把「该往哪儿看」的直觉整个翻了过来,我们在 STEP 2 回到这件事。
所以请把成功定义为每周被证明已死的凭据数,并且追踪「到撤销的时间」的分布而不是它的均值,因为泄露事故来自尾部。另有两个次级指标各值一行看板:有具名负责人的未关闭发现占比,以及被智能体上报为「无法判定」的发现占比——后者应当非零,因为一个从不说「我不知道」的智能体是在猜。
请明确声明这个智能体不做什么:它不关闭发现。一个发现的关闭,是签发方系统确认该凭据已无法通过认证之时。任何「以智能体自己的报告来关单」的流程,都安装了一个自我认证的评分器——与漏洞修复智能体里剖开的是同一个陷阱。
把它对准私有仓库的历史与非代码面,而不是公开仓库。
公开 GitHub 那个数字是上头条的那个,也是你的智能体最帮不上忙的那个,因为推送保护和十几个研究用爬虫早已覆盖了它。同一份报告里的三个发现会把工作重新指向别处:
- 私有仓库含有密钥的可能性是公开仓库的六倍——32.2% 对 5.6%。原因并不神秘:隐含的心智模型是「这个仓库是私有的,所以这把密钥没问题」,而且没人感受到一次公开提交会带来的那种压力。你自己的内部单体仓库,是你手上最肥沃的那片地。
- 2025 年有 28% 的事件完全源自源代码之外——Slack 消息、Jira 工单、Confluence 页面以及类似的协作工具。一个只看仓库的扫描器在结构上就看不见四分之一的问题,而这正是「自建一个智能体」而非「再买一个检测器」最大的覆盖面论证:智能体可以被对准一个压根没有扫描器的面,读一张工单,并在散文里认出一份凭据。
- AI 服务相关的密钥同比增长 81%,突破 127 万个;增长最快的十类检测器里有八类与 AI 服务相关——而 LLM 基础设施(编排、RAG、向量存储)的泄漏速度大约是核心模型厂商的五倍。你自己的智能体技术栈,是这份报告里增长最快的泄漏面。请一本正经地先扫它。
还有两条定范围的规则,能让你第一天就不至于背上一个没法用的积压:
- 扫历史,不是扫工作区。一份被删掉的密钥仍是一份有效的密钥,而且仍在每一份克隆里。那个删掉它的提交不是修复;请把整个可达历史——包括游离对象与未合并分支——都算进范围。
- 按凭据去重,不要按出现位置去重。一把密钥被提交进九个仓库,是一次轮换,不是九张工单。跳过这一步的团队会发现自己的「积压」大半是同样那二十个密钥,而真实数字其实对付得过来。
验证悖论,以及它强加给你的架构。
难的地方在这里,而它是一个设计约束、不是一个提示词工程问题。一串高熵字符串不是一个发现;一份有效的凭据才是。这两者之间的差,就是这个智能体的全部价值,因为「64% 仍然有效」那个数字说明有效性才是真正要紧的那根轴。而确立有效性的唯一办法,是把那份凭据出示给签发方服务。
那恰恰是你绝不可以交给智能体的那项能力。一个手握任意「捡来的凭据」、又有对外网络访问的智能体,正是造出 2026 年那几起最严重事件的那种配置——Transluce 的数据集就报出:智能体用在公开代码仓库里找到的开发者密钥,取到了它此前被拒的数据;这是被混淆的代理人最平淡无奇的那身打扮:智能体并没有窃取任何东西,它捡到了一把摊在外面的密钥并用了它,因为用了它就能把任务做完。
所以请把系统劈成两半,并把这道劈口做成一条硬边界:
- 智能体只看到候选,永远看不到密钥。它收到的是一个引用——仓库、提交、路径、行号、检测器类型、一个指纹——而绝不是凭据材料本身。这同时也让密钥不会进到你的追踪、你的模型厂商日志,以及拉取请求正文里;这与从智能体追踪里脱敏 PII是同一套纪律,也是「要在边界上做对、而不是事后加个过滤器」的理由。
- 一个验证器服务持有密钥。小、确定、里面没有模型。它有自己的工作负载身份、自己的出站白名单(精确列出它可以联系的凭据签发方)、强硬的限流,以及每一次出示的审计记录。它返回一个结构化判定——
live、dead、unknown——外加签发方愿意告诉你的关于主体与最后使用时间的信息,别的什么都不返回。 - 验证在构造上就是最小权限。调用该厂商提供的最廉价的身份端点,绝不去读数据。「我是谁」已经足以回答你唯一问过的那个问题。
这与其说是在防一个恶意智能体,不如说是在防一个普通智能体。只要用掉那把有效密钥是通往结果的最短路径,模型就会用它,而任何数量的系统提示词文字都无法可靠地阻止——这正是为什么解法是「那把密钥永远到不了上下文」。配套的那项控制,是把一枚蜜标对准你自己的扫描智能体:埋一份一旦被使用就报警的凭据,一周之内你就会知道你那条边界到底守不守得住。
请把验证器的出站规则按默认拒绝来跑,并把签发方逐个列举出来。你要防的那个失败是:一份属于你从未预料到的服务的凭据,被一次通往你从未审查过的主机的出站调用所「验证」——见智能体的出站控制。一份无法验证的凭据是一个正当的 unknown,它该进上报队列,而不是进一次「尽力而为」的尝试。
轮换是对一个智能体并不拥有的系统做写入。把它拆开。
「把密钥轮换掉」是四份活挤在同一个动词里,而其中只有两份是智能体的:
- 找出签发方与消费方。这把密钥是哪个系统铸出来的,以及它停止工作时什么会坏。这是横跨代码、配置、基础设施定义与部署清单的真正侦查工作,也是智能体最强的贡献——它枯燥、机械,而且正是轮换这件事被搁上好几年的原因。
- 铸出替代凭据并接上线。新凭据进密钥管理器、引用处更新、一个删掉硬编码值并改为从管理器读取的拉取请求。安全、可评审,而且就是一次普通的代码变更。
- 切换。部署、确认新凭据已在使用、盯着报错。这是负责人的决定,按负责人的时间表走。
- 撤销旧的那份。不可逆的那一步,也是唯一一个能关闭发现的那一步。
把前两份交给智能体,第四份永远不给。让这件事能上线的那条规则是:智能体可以创建凭据,永远不可以删除凭据。创建是增量的、可挽回的;撤销则是一次停机,而它的爆炸半径智能体看不见,因为它漏掉的那个消费方,按定义就是不在它读过的代码里的那一个。切换与撤销之间的那道闸,是一个被实测过的零使用窗口——多数签发方会暴露最后使用时间戳,而「旧凭据下连续 N 天无认证」是一个客观前置条件,自动化步骤可以据以行事。若签发方不暴露这类信号,那就是一个人类决定,而诚实的答复是把这件事说出来,而不是让智能体去猜。万一一次轮换真的出了岔子,恢复的纪律在修复智能体已经做过的事里。
请把轮换方案当作产物,而不是把补丁当作产物。一个以「签发方、消费方、替代用的 PR、具名负责人、零使用前置条件」交付的发现,一个人十分钟就能动手。一个以「删掉那一行的 diff」交付的发现比什么都不做更糟:它看起来已经关闭了,凭据却仍然有效,而下一次扫描再也找不到它。
这个智能体会自己造出来的两种失败。
两者都源自智能体在优化「你量的那个东西」而不是「你想要的那个东西」,而且两者都足够可预测,能在第一次运行之前就把工程做上去。
删掉那一行,然后宣布修好了。如果你的成功判据是「当前代码树里检不出密钥」,那么一个删掉该字符串的 diff 就完全满足它,而凭据的有效性一点没变。这是这一类里最常见的假通过,它会通过代码评审,因为那个 diff 看起来恰恰就是正确的改动;而唯一的防御是一个要求撤销回执的评分器——即签发方对「该凭据已无法通过认证」的确认。别的都不算。
靠重写历史让发现消失。一个被要求「把密钥从仓库里移除」的智能体,迟早会提议重写历史,而这在三件事上都错了。它没有撤销任何东西,所以凭据仍然有效。它会让每一份既有克隆失效,并弄坏每一个 fork 与每一个开着的拉取请求。而那份密钥早已在你的掌控之外——在 fork 里、在 CI 日志里、在平台缓存里、在第三方镜像里——所以这次重写以真实代价买来一个幻觉。顺序没有商量余地:先撤销,清洗放到之后,或者永不清洗。清洗是一个有负责人、有维护窗口的「整理项目」,不是一个修复步骤,而且它永远不该出现在这个智能体的动作空间里。
- 禁的是机制,不只是行为。智能体的工具面里压根不要有
filter-repo、不要有强制推送、不要有任何改动历史的操作。写在提示词里的禁令是一个先验;一个不存在的工具才是一条边界。 - 把「N 天后仍然有效」做成一个会升级的告警。这个发现应当自己越喊越响,因为那个 64% 就是它不喊时会发生的事。
- 让检测与执行两半跑在不同的沙箱里。读取不可信仓库内容的那一半,不该是能往你的密钥管理器里写的那一半——这是沙箱与安全执行里的标准劈分。
用你自己的事件历史来评测它,并接受较低的精确率。
评测集你早就有了,而多数团队从不去建:你们组织处理掉的每一起密钥事件,连同当时的仓库状态、凭据的签发方、后来证明确实要紧的那些消费方,以及撤销实际完成的日期。把它们回放一遍。要问的不是智能体能不能找到那串字符串——扫描器找到过,否则你不会有这份记录——而是它是否指认出了同一个签发方、同一组消费方、同一位负责人。
在精确率与召回率的取舍上,这个智能体很特别,而通常的建议在这里要反过来。在别处,一个吵闹的智能体就是一个死掉的智能体,因为每一个误报都要花人去评审。而在这里,验证器便宜、确定、无人值守,所以一个最终被判为已死或无效的候选,只花掉一次自动调用、不花任何人的注意力。请为召回率调参,让验证器去做过滤,并把你的精确率预算花在验证之后那一步——在那里,一份错的消费方清单会造成停机,而一位漏掉的负责人会让一个发现搁上四年。
- 按消费方清单的完整性打分,并对遗漏施加惩罚。漏掉一个消费方,正是一次轮换变成一次事故的方式;多列一个只花掉评审者一分钟。
- 把上报率当作质量信号,而不是失败。代码库没变、而「无法判定」率却在下降,意味着智能体学会了断言而不是核查。
- 把产出喂进凭据权限复核。这个智能体产出的那份「签发方—消费方」映射,正是智能体凭据的权限复核通常缺的那份清册,也是这个项目造出来的最可复用的东西。
按这个顺序建,而且如果数字不好看,做完第二步就停。一:验证器服务,带自己的身份与一份默认拒绝的出站清单——一周的活、不涉及模型,而且对你现有的积压立刻有用,因为它会告诉你今天开着的那些发现里哪些还有效。二:把智能体对准私有仓库的历史,以及一个非代码面(你的工单系统最容易),并按凭据去重。三:做「签发方—消费方」映射,每个发现配一位具名负责人。四:替代用的拉取请求。轮换自动化放在最后,而且可能永远不值得做——如果到第三步时,你那条「到撤销的时间」分布已经是以天而不是以年计量,这个项目就已经把自己赚回来了。