返回所有文章
发布于 · 作者 Renaud Deraison

那把密钥从未过期

Truffle Security 花了四年,从 git 历史、Hugging Face 数据集、Docker 镜像和 CI 日志里捞出 AWS 密钥。在能够重新验证的那些当中,88% 至今仍可通过认证。仍然有效的密钥年龄中位数是五年,2,505 名用户从未轮换过自己的密钥,其中 929 人身上还挂着 AWS 在公开场合发现密钥时附加的隔离策略。没有人漏掉任何检测。Bromure Agentic Coding 把负责签名的那一半留在 VM 之外,因此代理泄露出去的东西,在离开的那一天就已经死了。

找出泄露的凭据是一个已经解决的问题。Truffle Security 做了四年,拿得出 431,875 条 AWS 发现记录。没解决的是后面那一半,也就是得有人登录并删掉密钥的那一步。那件事七次里只发生一次。

Truffle Security 本周发布了一份普查, BleepingComputer 在周四跟进报道。 自 2022 年 8 月起,这家公司持续在 AWS 访问密钥公开现身的地方收集它们:git 历史、Hugging Face 数据集、Docker 镜像、软件包仓库、CI 日志。然后再确认它们是否还能用。

这份报告 统计出 431,875 条已验证的 AWS 发现记录,去重后得到横跨 50,654 个不同账户的 64,024 把唯一访问密钥。 其中有 10,616 组带有足够材料可以重新测试。其中八十八个百分点至今仍可通过认证。那是 9,308 把今天还活着的密钥,过去四年里任何人都可能从某个公开表面上把它们捡走。

他们把验证范围压得很窄,只用只读的元数据调用:sts:GetCallerIdentityiam:ListAccessKeys、 策略名称枚举、一次预算读取,以及每个账户一次 Cost Explorer 调用。他们没有读取任何数据,也没有改动 任何东西,并在发布前通知了 10,616 位所有者中的 10,260 位。

接着看看这些密钥有多老。

五年,而且还在往上加

仍在运行的密钥,年龄中位数是 1,831 天。最老的是 17.4 年。整组数据里只有 25 把,也就是百分之一的 十分之九,来自最近三十天。

这样的分布描述的是沉积物,而不是一条新鲜事故被抓住又被清干净的河流。密钥泄露之后就一直泄露下去, 因为 AWS 的静态访问密钥没有到期这回事:没有时钟,没有续期,没有十八个月后就过期的证书。它会一直 有效,直到有人打开控制台把它删掉。Truffle 测量了那个「有人」出现的频率。在研究人员能够枚举密钥的 用户里,2,903 人中有 398 人在泄露密钥旁边放了一把更新的密钥,也就是 13.7%。其余 2,505 人从未轮换过。

这也不能怪到检测那一步,因为 Amazon 早就把发现的工作做完了。当 AWS 在公开场合看到自家的密钥,它会 给那位用户挂上一个叫 AWSCompromisedKeyQuarantine 的策略,收紧这把密钥能做的事,并给该账户发邮件。 没有人需要开口要求。Truffle 发现有 929 位 IAM 用户,占 7,590 位活跃用户的 12%,此刻正挂着那个策略。 其中一百一十二人挂的是最初版本,说明 AWS 至少在三年前就标记了他们,而他们的密钥现在仍会响应。

检测生效了,邮件也发了,三年之后密钥依然好用。

一把泄露 AWS 密钥的一生第 0 天密钥抵达公开表面提交、镜像层、CI 日志、数据集已检测AWS 附加AWSCompromisedKeyQuarantine并发邮件通知账户所有者没有东西让它过期没有 TTL,没有续期除非有人动手删除第 1,831 天今天仍可通过认证的密钥年龄中位数17.4 年这组数据里最老的有效密钥有人发过替换用的密钥吗13.7% · 398 人86.3% · 2,505 人从未轮换、替换或清掉那把泄露的密钥
AWS 的静态访问密钥没有到期,所以一次泄露没有结束日期。唯一能把它关上的是有人去删掉这把密钥,而在 2,903 位可枚举的用户中,那只发生了 13.7%,连 AWS 自己标记并隔离的那 929 位也包含在内。

泄露面搬到了没有删除键的地方

整份普查里最大的单一来源是 Hugging Face:横跨 3,394 个数据集的 8,482 把唯一有效密钥,以及 17.9% 的 root 密钥比例,远高于其他群体。

这条管线的另一端,Truffle 早就测过了。六月时团队 把 Hugging Face 上每个公开数据集都克隆了一份: 1.869 亿个唯一文件、7.6 PB、约 815,000 个数据集仓库。他们把 Parquet、Arrow、JSONL 与归档文件摊平成可扫描的文本,并验证找到的每一项。结果是 6,003 个数据集里有 221,303 组有效且唯一的凭据:11,496 把 AI 供应商密钥、横跨 3,811 个项目的 8,557 把 Google Cloud 服务账户密钥、8,594 组可用的数据库登录信息、3,343 把能通过 STS 身份检查的 AWS 密钥,以及 349 个 GitHub 个人访问令牌,其中 223 个能推送代码,130 个能改写 CI 工作流。

他们的两个例子显示一次失误能跑多远。有人把一家巴西金融科技公司的 AWS 密钥贴进聊天机器人,如今它在 不同语料库里被复制了大约十八次。以同样方式被捕获的一把 Infura 密钥,最后落在 1,131 个数据集和 10,162 个不同的文件位置里。Truffle 找到的唯一有效秘密中,有四十四个百分点出现在一个以上的数据集。

然后人们拿这些数据集去训练。StarCoder 有文档记录的训练数据含有 25,217 把这类密钥;Swallow 有 22,484 把;OLMo 3 有 21,278 把。大型专有模型的语料库不对外公开,所以外界没有人知道。

Truffle 给出了直白的结论:轮换仍是唯一的解法,因为没有人能回头去清训练数据。任何曾经进到公开仓库、 网页或聊天机器人的密钥,都该当成已经烧掉。

一组凭据,没有回头路一把有效密钥贴进聊天机器人、提交或写进日志以数据集公开6,003 个 HF 数据集里有有效凭据被大量复制44% 的有效秘密出现在多个语料库被拿去训练StarCoder 25,217Swallow 22,484OLMo 3 21,278一把 Infura 密钥,来自单单一次对话:1,131 个数据集、10,162 个文件位置。删掉原始文件,一份也碰不到。唯一能收尾的一步,是到供应商那里把密钥删掉,而这一步只发生 13.7%。
凭据一旦进入公开数据集就收不回来。Truffle 发现 44% 的有效秘密在不同语料库之间重复出现,一把 Infura 密钥落在 1,131 个数据集里,开放模型有文档记录的训练数据中还藏着数万把可用密钥。删掉原始文件,对下游毫无作用。

那份清单上的每个来源,都是代理会写出来的东西

再看一次 Truffle 去哪里采买:git 历史、Docker 镜像、软件包仓库、CI 日志、数据集上传。那些都是构建 产物,而且正是今天的编码代理在无人看管的深夜,以任何团队都审不完的速度制造出来的东西。

一个在你睡觉时清理待办的代理,会写提交、改写 lockfile、构建镜像、推分支、灌满日志。这其中每一件 都是发布表面,而整段期间你的 ~/.aws/credentials 都在它伸手可及之处,因为 SDK 本来就是被设计成 去那里找它。

编码代理写出这些产物的速度,比以往任何工具都快,而那 13.7% 没有动过。

负责签名的那一半留在你的 Mac 上

Bromure Agentic Coding 把代理跑在 Apple Virtualization 框架上的一次性 Ubuntu VM 里,对外唯一通道 是主机端的代理服务器。在这个设计里,AWS 需要特别处理。SigV4 从不把秘密放上线路,因为 SDK 是在进程内拿它算出一个 HMAC,所以代理服务器在传输途中没有东西可以替换。于是 Bromure 改为搬动签名 这件事本身。

在 VM 里,~/.aws/config 指向一个 credential_process 辅助程序。当 SDK 索取凭据时,辅助程序会返 回真正的访问密钥 ID,搭配一组每次会话重新铸造的四十字符假秘密。访问密钥 ID 是标识符而不是秘密, 它是用来表明哪个 IAM 用户在调用的那一半。秘密访问密钥才是负责签名的那一半,而它从未进入 VM 的 地址空间。Bromure 甚至不把 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY 导入客户机环境,理由是环境 变量会从 /procps -E 与 shell 历史里漏出去。VM 拿到的只有一个区域字符串,别无其他。

SDK 签出的请求,其签名不可能正确。在出去的路上,主机把那个签名剥掉,用真材料重新计算 SigV4。aws、 boto3 与 terraform 都照常工作。任何绕过代理服务器的东西,都会从 Amazon 收到 InvalidSignatureException,而那正是你想要的失败方式。

现在把一个 Bromure 工作区丢进 Truffle 的方法论里。他们把一把密钥计入的门槛,是一次签名过的 sts:GetCallerIdentity 回来是有效的。假设一个被入侵的依赖包从那个客户机里捞走凭据文件,或者代理 被说服去 cat 它,或者某次构建把它内嵌进公开的 bundle。跑出去的是一个标识符,加上四十个从来就不是 秘密的字符。它在泄露的当天就失效,所以永远不会加入那层沉积物,后面也不会拖着五年的长尾。

这同时拿掉了那个要等人类完成的轮换步骤。真正的秘密只住在一个地方,也就是你 Mac 上配置文件的「凭据」 面板。在那里改掉,下一个会话就会取用。没有人需要去查九十次深夜运行里,是哪一次写出了哪个产物。

笔记本上的代理~/.aws/credentialsaws_access_key_id = AKIA…aws_secret_access_key = <真的>代理读它,SDK 拿它签名,而它写出的每一个产物都可能把它带走一次提交、一层镜像、一份 CI 日志、一个数据集sts:GetCallerIdentity → 有效中位数再来五年都是这样Bromure 工作区里的代理VM 内 · credential_process 辅助程序AccessKeyId = AKIA…SecretAccessKey = <40 字符假值>真秘密在 Mac 上,从不进入 VM代理服务器剥掉注定失败的签名并重新签名同一个产物,就算被捞走sts:GetCallerIdentity → InvalidSignatureException
Bromure 工作区里的 AWS 凭据:访问密钥 ID 用来表明调用者身份,会进到 VM;负责签名的秘密访问密钥则不会。客户机签出一个注定失败的请求,主机再用真材料重新签名,而任何从 VM 捞走的东西,都会在普查用来清点有效密钥的同一项 STS 检查上失败。

一个比签它的密钥还要窄的签名请求

普查的另一个重点是触及范围。在 817 把能连到某家企业的密钥里,有 768 把给出账户的完整控制权:526 把 root 密钥,以及 242 个持有 AdministratorAccess 的 IAM 用户。其中一百三十把 root 密钥位于组织管理账户上,也就是统管组织内每个成员账户的那个账户。在研究人员能够枚举的用户里,有 976 人持有 AdministratorAccess,比例是 84%。

那些是多年前为了方便而铸出来的密钥,用途是一件只需要三个权限的工作。

Bromure 的 Guardrails 设置会在使用的当下把凭据收窄,让你完全不必记得要在源头收窄它。它是代理服务器 里的一个主机端策略引擎。对 AWS 而言,它会从 DynamoDB、Lambda 这类 JSON 协议服务的 X-Amz-Target 标头读出动作名称,从 EC2、IAM、SQS 这类查询协议服务的 Action= 参数读出动作名称,而对 S3 则退回 使用 HTTP 方法判断。Delete*Terminate*Remove*Purge*Destroy* 被归为破坏性; Get*List*Describe* 被归为读取。把配置文件调成只读,变更操作就会以一个硬邦邦的 403 回来,代理会把它读成一次普通的 API 失败。调成拦截破坏性操作,创建与更新会通过,删除不会。

执行这件事的是你的 Mac,不是 VM,所以一个被说服去做什么的代理,没办法用讲道理的方式绕过去。你 主机拿去签名的凭据,最后比凭据本身还要窄,而在一个 84% 可枚举用户都握着管理员权限的群体里,这件事 很值得。

记录比账单先出现

再从报告里挑一个数字。在研究人员能读到预算的 2,754 个账户中,只有 262 个设置过任何预算告警,也就是 9.5%,其上限中位数是八美元。同一组账户在七月花了 420,631 美元,其中五十个超过 1,000 美元,九个超过 10,000 美元。这些所有者多半会在账单上跟入侵者初次见面。

Bromure 会在工作进行的同时写下记录。主机签出的每一个请求,都会在窗口 → 安全时间线留下一行 credential.aws_sign,带着服务、方法、主机、区域与掩码后的访问密钥 ID,和软件包抓取、防火墙裁决与 凭据替换并列在一起。Bromure 把这份日志留在 Mac 上,VM 里的任何东西都改不了它。若要更严格的版本, AWS → 使用时需批准会把每次签名调用变成一则同意提示,并给出有时限的授权,所以一整个下午的实际 工作只会问你一次。

Bromure 把同样的想法用在更前面一步,也就是你第一次把配置文件叫起来的时候。它会让你导入的代理配置 先过一轮脱敏:结构化的 JSON、TOML 与 YAML 按键名过滤,匹配 tokensecretpasswordapikeycredentialauthorizationprivate_keyaccess_key;纯文本则按令牌形状过滤,匹配 AKIAASIAsk-ant-ghp_glpat-AIzanpm_。无论你 Mac 上的 dotfile 里放着哪些真秘密, 它们都不会跟着其余配置一起搭车进 VM。

这份普查证明了什么

Truffle Security 这件事做得很正派:只读调用、不碰任何数据、在发布前通知了 10,616 位所有者中的 10,260 位。AWS 的表现也比标题暗示的要好,因为那个隔离策略,正是 Amazon 在没人要求的情况下自己找出 泄露密钥并警告所有者。检测环节的两半都尽到了本分。

结果仍然是 9,308 把有效密钥、年龄中位数五年,以及 13.7% 的轮换率。

那个失灵的控制项,要求一个人在失误发生的数个月甚至数年之后,去一台可能已经不归他管的系统上,为一把 完全没有任何异常迹象的密钥完成一件杂事。这种形状的控制项在规模面前必然失灵,而且早在有什么东西开始 在深夜写提交之前,它就已经在失灵了。

所以别再指望那件杂事扛起全部重量。把一组从来就不是凭据的凭据放进工作区,普查就没有东西可数,语料库 就没有东西可复制,而那条五年长尾就变成别人的事了。


资料来源:Truffle Security「Leaked Corporate AWS Keys Held Full Admin Rights」(2026 年 8 月 19 日) · Truffle Security「Scanning 7.6 Petabytes of HuggingFace Training Data for Secrets」(2026 年 6 月 1 日) · Truffle Security「Introducing TruffleHog AWS Analyze」(2026 年 8 月 20 日) · BleepingComputer「Hundreds of leaked AWS keys give full control over corporate accounts」(2026 年 8 月 21 日) · Cybernews「Massive exposure: researchers test leaked AWS keys, 9 out of 10 still authenticate」(2026 年 8 月 21 日)