AI 开发平台密钥泄露自查:环境变量、Bedrock、CI 怎么轮换

Wiz 在 2026-10-30(美国时间)把十月一串 AI 开发平台事故串成「Black October」:至少 9 家披露了安全事件,公开信息里攻击者进去后都在翻环境变量,尤其是能调大模型的密钥。站内已发过这条快讯。按 Wiz 报告、AWS Bedrock 处置文档、GitHub 泄露密钥补救文档和 OpenAI API 密钥安全指引(2026-11-02 北京时间查阅)整理。不复现攻击,只写文档里写明的自查与轮换步骤。
先认清:攻击者要的是环境变量里的 AI 钥
Wiz 写明:没有找到把这 9 起事件串起来的同一个漏洞或同一条依赖链。Fireworks、Zeabur、Lightning 归因于凭证被拿;Railway 初步说是构建基础设施提权;Warp 指向第三方依赖;OpenCode 指向遗留系统。共同点是「进去之后专门找存着的环境变量,重点是 AI 访问凭证」。
下游滥用被 Wiz 叫做 LLMJacking。他们观察到两把企业 Bedrock 密钥:第一把约 30 小时内约 80 万次调用、约 90% 成功;第二把约 13 小时内约 170 万次调用。按标价估算,这两例合计超过 10 万美元用量。Northflank 状态页要求客户假定环境变量已被解密,立刻轮换全部密钥。站内此前的OpenCode 控制台密钥泄露也在这一波里。
删掉仓库里的那一行密钥,不等于密钥失效——GitHub 和各模型厂商都把「先吊销」写成第一步。
自查第 1 步:把「钥可能落过的地方」列成表
对照 Wiz 写到的攻击面,把团队实际用过的托管面摊开。按常见落点逐项打勾。
| 落点 | 你要核对什么 | 处置原则(官方口径) |
|---|---|---|
| AI 开发 / 部署平台上的环境变量 | OpenAI、Anthropic、Bedrock、各大模型网关、向量库、对象存储密钥是否曾写入平台 Secrets / Env | 假定已暴露则全量轮换(Northflank 通告口径);到原厂控制台吊销旧钥 |
| 本机与容器环境变量 | OPENAI_API_KEY、ANTHROPIC_API_KEY、AWS_ACCESS_KEY_ID / Bedrock bearer、各类 *_API_KEY | OpenAI:用环境变量存钥,勿写入代码;轮换后更新所有引用处 |
| CI / CD(GitHub Actions 等) | 仓库 / 组织 / Environment Secrets;工作流日志是否曾打印过密钥 | GitHub:日志里出现未脱敏值 → 删日志并轮换;定期审查并轮换已登记密钥 |
| Git 历史与公开仓库 | 误提交的 .env、notebook、配置样例、fork / gist | GitHub:泄露密钥视为已失陷;删提交或重建仓库不能替代吊销 |
| 云厂商 API 钥面板 | Bedrock 长短期 API key;IAM 用户上的 service-specific credential | AWS:长钥可停用 / 重置 / 删除;短钥需作废生成会话或 Deny bearer 调用 |
别和提示词注入混在一块:注入是骗 Agent 把数据送出去(见提示词注入防护清单);这篇讲的是密钥已经以明文或平台密文形式,落在别人可能读到的地方。扩展后门那类自查(如Cursor 扩展后门自查)也替不了这篇的平台密钥轮换。
自查第 2 步:Bedrock 密钥按官方流程止血
Wiz 那两个案例,失陷的都是企业 Bedrock 密钥。AWS 文档把密钥分成两类,处置不一样:
- 长期 API key:可在 Bedrock 控制台 API keys → Actions 里 Deactivate(先停)、Reset key(换新密码)、或 Delete(永久删除)。API 侧对应
UpdateServiceSpecificCredential(Status=Inactive)、ResetServiceSpecificCredential、DeleteServiceSpecificCredential。这些操作要用普通 AWS 凭证,不能拿已失陷的 Bedrock API key 去改它自己。 - 短期 API key(最长约 12 小时,或不超过生成它的会话时长):控制台不会列出单把短钥的停用按钮。文档要求:作废生成该钥的 IAM 会话,或给相关身份挂 Deny 策略,禁止
bedrock:CallWithBearerToken和bedrock-mantle:CallWithBearerToken——只 Deny 前一个拦不住 Mantle 端点。
# 长期钥:立即停用(把 ID 换成创建时返回的 ServiceSpecificCredentialId)
aws iam update-service-specific-credential \
--user-name bedrock-api-user \
--service-specific-credential-id "${ServiceSpecificCredentialId}" \
--status Inactive
# 长期钥:重置(生成新密钥材料;已过期则删掉重建)
aws iam reset-service-specific-credential \
--user-name bedrock-api-user \
--service-specific-credential-id "${ServiceSpecificCredentialId}"
AWS Security Blog 把顺序写得更靠前:能用 STS 临时凭证就别发长期 API key;必须用 bearer 时优先短钥;长期钥用条件键卡住最长有效期(创建时可限制天数),并收紧 AmazonBedrockLimitedAccess 里用不到的权限。同时核对本月 Bedrock / 跨区域推理用量有没有异常。
自查第 3 步:GitHub 上「泄露 → 吊销 → 换新」
GitHub《Remediating a leaked secret》写得很直:密钥一旦泄露,就按已经失陷处理。只从代码里删掉、再推一个 commit、甚至删库重建,都挡不住别人继续用那把还活着的钥。
- 在密钥颁发方控制台(OpenAI / Anthropic / AWS / 云数据库等)吊销或删除旧密钥。若担心业务中断:先创建同等权限的新钥 → 应用切到新钥并确认可用 → 再吊销旧钥。
- 把新钥写进 GitHub Actions 的 Secrets(仓库 / 组织 / Environment),不要写回工作流 YAML。
- 若工作流日志里曾打出未脱敏的密钥:按文档删除相关 run 日志,并轮换该密钥。
- 打开 push protection(Secret Protection)和个人账号的「Push protection for users」,降低再次推上去的概率。
- 定期审计已登记 Secrets:不用的删掉;还在用的轮换,缩短失陷窗口。生产环境可用 Environment secrets + required reviewers,让敏感作业先过人审。
GitHub Actions 安全参考还提醒:别把整段 JSON/YAML 塞进一个 Secret(脱敏靠精确匹配,大包容易漏);派生出的 JWT、Base64 值也要单独登记,否则日志里红不掉。
自查第 4 步:OpenAI 等模型厂商控制台
OpenAI《Best practices for API key safety》和《Keeping your account secure》里,跟「平台环境变量被翻」直接相关的几条:
- 每人 / 每集成一把独立钥,禁止共享;可按项目拆权限(All / Restricted / Read Only)。
- 创建时带过期时间,并建立轮换流程:到期前开新钥 → 改应用 → 确认后再撤销旧钥。组织或项目可强制最大密钥寿命。
- 钥只放服务端环境变量或密钥管理服务,不进浏览器、移动端、仓库。
- 开用量页与支出硬限制(hard enforcement);只开告警拦不住流量。怀疑泄露:在 API Keys 页删除该钥 → 核对 Usage → 必要时联系支持。
- 有条件再加 IP allowlist:钥泄露了,陌生网段也打不进来。
Anthropic、其他网关、向量库控制台按钮名字不同,顺序一样:吊销 → 换新 → 更新所有平台 Env / CI Secret → 核对近 30 天账单。用过 Wiz 点名那批平台托管密钥的团队,默认按全量轮换做。
常见坑
- 只改平台上的 Env,没去原厂吊销。攻击者手里的旧字符串仍然能打 API;平台面板里的「新值」救不了旧钥。
- Bedrock 短钥当长钥处理。短钥没有控制台「停用」按钮,要去作废会话或 Deny 两个
CallWithBearerToken动作。 - 只 Deny
bedrock:CallWithBearerToken。文档写明 Mantle 端点要另 Denybedrock-mantle:CallWithBearerToken,少一条就没封死。 - 轮换后漏更新 CI / 第二套部署环境。半截切换会导致正常流水线失败,又诱使人把旧钥临时加回去。
- 清理 Git 历史当成首要动作。历史清理可以延后、需要和安全负责人一起评估;吊销必须立刻做。
完成标准
- 曾写入出事或可疑平台的每一把 AI / 云密钥,都在原厂控制台显示为已删除、已停用或已重置。
- 本机、容器、平台 Env、GitHub Secrets、密钥管理服务里的引用已全部换成新钥,旧值搜不到。
- Bedrock:长钥已 Inactive/Reset/Delete;短钥相关会话已失效或身份已 Deny 双 bearer 动作。
- 近 30 天(至少从 2026-10-01 起)各厂商 Usage / 账单已人工扫过,异常峰值有记录。
- GitHub push protection 已开;工作流里不再出现明文密钥;不需要的 Secrets 已删。
最后
把团队用过的 AI 平台列一张表,先把环境变量里出现过的模型钥在原厂吊销并换新;Bedrock 用户按第 2 节把长钥停掉或重置。五条完成标准打完勾,再去看用量页——比事后追 10 万美元账单便宜。