Rust Miri 缓存输出泄漏问题的工程防护思路
Rust Miri 本身是用来发现未定义行为的工具,但它运行在 CI 中时也会接触进程环境。旧版 Miri 曾把环境变量保存到 target/,如果工作流再把这个目录放进 GitHub Actions 缓存,并允许低信任 Pull Request 恢复缓存,原本只在 CI 步骤中出现的 secrets 就可能跟着构建输出留下来。工程上的重点不是停用所有 Miri,而是让 Miri 任务不携带业务凭据,也不把它产生的 target/ 当作可跨信任边界复用的缓存。
官方资料:https://blog.rust-lang.org/2026/09/21/github-actions-leaking-secrets-when-miri-output-is-cached/
Miri 项目地址:https://github.com/rust-lang/miri
GitHub 缓存文档:https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching
先按四个条件判断是否进入风险面:CI 是否运行cargo miri,该步骤是否能读取 secrets,是否缓存了target/,以及低信任 PR 是否能恢复这份缓存。命中越多,越应该先隔离 secrets、停止缓存 Miri 的target/,再清理旧缓存并评估凭据轮换。
先把 Miri 缓存输出的风险链拆开
这类问题通常不是单个配置造成的,而是四个普通动作叠加:Miri 需要在多次调用之间保留部分构建相关环境;工作流把构建目录缓存起来;主分支或受信任分支能够写入缓存;低信任 PR 能够在后续运行中读取缓存。只要敏感环境变量在 Miri 步骤可见,缓存就不再只是“加速依赖安装”的目录。

官方公告把影响条件写得很具体:运行 cargo miri 的 job 有 secrets、工作流缓存 target/,并且缓存可以被 Pull Request 使用。不要只盯着 actions/cache,第三方 Rust 缓存 action 也可能把目标目录纳入缓存范围。
盘点工作流到底暴露了什么
先在仓库中查出 Miri、缓存 action 和目标目录。这个命令只读取工作流文本,不会打印 secrets 的值;输出应作为整改清单,而不是把整份 CI 日志上传到公共位置。
# 在仓库根目录执行,定位 Miri、缓存 action 与 target/ 的声明。 rg -n --glob '.github/workflows/**' 'cargo miri|miri|actions/cache|rust-cache|target/' . # 单独找出工作流级和 job 级的 secrets 继承,便于缩小权限范围。 rg -n --glob '.github/workflows/**' 'secrets:|secrets\.|env:' .
把结果按 job 记录四列:是否运行 Miri、是否能看到 secrets、缓存路径是什么、缓存的读取者是谁。env: 写在 workflow 或 job 级别时,往往比一个 step 的 env: 影响范围更大;前置步骤通过环境文件或生成文件传递值,也应视为同一条数据流。
还要区分“缓存 Cargo 下载依赖”和“缓存编译输出”。前者可以服务普通构建,但仍不能放入令牌;后者可能包含工具生成的元数据,尤其是 target/,不应在低信任 PR 与受信任分支之间共享。
让 Miri 步骤不携带业务 secrets
最小修复是把 Miri 从发布凭据所在 job 中拆出来。Miri 只负责检查 Rust 代码的未定义行为,不需要云密钥、部署令牌或生产 API 密钥;需要访问私有依赖时,也应采用最小范围、短生命周期的凭据,并重新判断缓存是否能跨信任边界读取。
# 示例:Miri job 不继承 workflow 级 secrets,避免测试工具接触发布凭据。
name: rust-ci
on: [push, pull_request]
jobs:
miri:
runs-on: ubuntu-latest
# 这里故意不设置 secrets 环境变量,也不复用发布 job 的 env。
steps:
- uses: actions/checkout@v4
- name: 安装 Miri
run: rustup component add miri --toolchain nightly
- name: 运行 Miri 测试
run: cargo +nightly miri test
release:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 只有真正需要发布的步骤才读取部署凭据。
- name: 发布
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
run: ./ci/release.sh
上面的版本只示意权限边界。不要把 secrets 放回 workflow 顶层,再期待 Miri 步骤“不会主动使用”它;环境变量一旦进入进程,工具、构建脚本或依赖都可能看到它。对于来自外部贡献者的 Pull Request,优先使用不含 secrets 的 pull_request 流程,发布则放到受保护分支的独立 job。
不要把 Miri 的 target/ 当成通用缓存
GitHub Actions 的缓存适合复用明确、可重建且不含敏感信息的输入。缓存 action 在命中时会恢复路径,在成功完成后也可能用当前路径创建新缓存;因此“这次没有打印 secrets”不等于缓存内容没有风险。
# 示例:Miri job 不缓存 target/;让每次检查使用隔离的构建输出。
miri:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装 Miri
run: rustup component add miri --toolchain nightly
# 不使用 actions/cache 缓存 target/,避免跨运行复用 Miri 产物。
- name: 运行 Miri
run: cargo +nightly miri test
unit-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 缓存 Cargo 下载目录
uses: actions/cache@v4
with:
# 这里只缓存下载内容,不把 target/ 放进共享缓存。
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: 运行普通测试
run: cargo test --all-targets
依赖缓存也不是天然安全区。GitHub 文档明确提醒不要把访问令牌或登录凭据放在缓存路径中;缓存路径应尽量只包含可由锁文件和工具链重新生成的依赖数据。若团队必须缓存 target/ 以缩短普通测试时间,至少不要让 Miri job 写入同一缓存键,也不要让低信任 PR 读取受信任分支生成的目标目录。
补上权限、日志和旧缓存处置
修复配置后,还要处理已经生成的缓存。旧缓存不会因为工作流文件改了就自动消失;应删除受影响的缓存,并按照组织的凭据响应流程判断是否轮换可能暴露的令牌。文章讨论的是工程防护,不假设某个项目一定已经发生实际窃取。
# 用 GitHub CLI 查看仓库缓存条目;先确认仓库和权限,再按组织流程删除受影响条目。 gh cache list --limit 100 # 列出工作流中的高风险组合,供代码审查复查;不读取任何 secret 值。 rg -n --glob '.github/workflows/**' 'cargo +?nightly miri|cargo miri|target/|secrets\.' . # 检查本地实际使用的 Rust 工具链,避免把“已修复”误当成任意 nightly 都已更新。 rustup show active-toolchain
日志中不要输出环境变量、完整配置对象或带令牌的命令行。只记录“哪个 job 运行了 Miri、是否启用 target/ 缓存、清理动作是否完成、工具链版本是什么”这类可审计事实。若组织决定轮换令牌,应把轮换时间、受影响范围和回滚联系人记录在安全变更单中,而不是写入构建日志。

发布前用四类检查确认没有回退
Rust 官方公告说明,后续 nightly 将不再让 Miri 全量保存环境变量,但不要把工具链升级当成唯一防线。缓存路径、job 权限和第三方构建脚本仍然需要独立检查。发布前可以按下面的清单复查:
| 检查项 | 合格状态 | 发现问题时的动作 |
|---|---|---|
| Miri 工具链 | 记录实际 nightly,并确认使用了包含修复的版本 | 更新并固定工具链,再重新审阅缓存和权限 |
| 敏感输入 | Miri job 没有业务 secrets 或不必要的令牌 | 将 secrets 下沉到独立发布步骤 |
| 缓存范围 | Miri 不写入可跨信任边界复用的 target/ | 删除该缓存路径或完全关闭该 job 缓存 |
| 历史缓存 | 受影响缓存已清理,凭据风险已评估 | 清理缓存并按响应流程轮换凭据 |
如果一个仓库只在受保护分支运行 Miri,且缓存从不被外部 PR 恢复,风险面会小很多,但仍不建议让不必要的 secrets 进入 Miri 进程。把“谁能写入缓存”和“谁能读取缓存”分别画出来,通常比只看缓存 key 更容易发现跨信任边界的问题。
几个容易混淆的边界
只升级 nightly 就够了吗?
不够。升级可以消除公告所描述的 Miri 全量环境保存行为,但工作流中的 build script、第三方 action 和自定义测试工具仍可能把环境写入构建产物。secrets 最小化和缓存隔离应继续保留。
只缓存 Cargo registry 会不会自动安全?
不会自动安全。它比缓存 target/ 更容易限定范围,但仍要确认路径中没有令牌、私有配置或构建脚本写入的敏感文件。GitHub 的缓存文档把“缓存路径可被读取者访问”作为基本前提。
Pull Request 不能写缓存,还需要担心吗?
需要区分写和读。常见配置是受信任分支写入,Pull Request 只恢复;如果缓存中存在敏感输出,不能写入并不代表不能读取。应同时审阅缓存读取范围、分支策略和事件触发方式。
Miri 任务完全禁用是不是最稳妥?
它能快速降低当前风险,但会失去对未定义行为、数据竞争和部分别名规则的动态检查。更合适的长期方案通常是保留无 secrets、无共享 target/ 缓存的 Miri job,把发布凭据和构建加速策略放到不同信任边界。
归根结底,Rust Miri 缓存输出泄漏问题提醒我们:构建产物也要按数据敏感度治理。先拆出 Miri、secrets、缓存路径和 PR 读取者四个条件,再落实步骤级凭据、缓存隔离、旧缓存清理和工具链复查,才能让修复从一次性公告响应变成可持续的 CI 安全基线。
GitHub Actions 代理任务怎样设计可追溯的权限边界
- 上一篇
- GitHub Actions 代理任务怎样设计可追溯的权限边界
- 下一篇
- Kubernetes 边缘场景的升级节奏怎样结合 KCD 2026 信息
-
- 科技周边 · 业界新闻 | 50分钟前 |
- GitHub Universe 2026 的开发者代理审查工作流拆解
- 474浏览 收藏
-
- 科技周边 · 业界新闻 | 52分钟前 | kubernetes · AI基础设施 Kubernetes 互操作性 CNCF 云原生基础设施
- CNCF 开源基础设施互操作性公告中的工程信号
- 214浏览 收藏
-
- 科技周边 · 业界新闻 | 56分钟前 |
- Kubernetes 边缘场景的升级节奏怎样结合 KCD 2026 信息
- 240浏览 收藏
-
- 科技周边 · 业界新闻 | 58分钟前 |
- GitHub Actions 代理任务怎样设计可追溯的权限边界
- 362浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 |
- CNCF 2026 AI 与云原生项目落地应关注哪些接口
- 235浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 |
- Kubernetes 1.37 Garhwal 的升级检查重点与兼容边界
- 436浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | github · 业界新闻 · GitHub 代码审查 Pull Request Octoverse 2026 代理开发
- GitHub Octoverse 2026 的提交增长怎样反映代理开发趋势
- 130浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | github · 人工智能 · GitHub benchmark ReviewBench 代码审查代理 AI代码审查
- GitHub ReviewBench 怎样评估代码审查代理的真实缺陷
- 112浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | Copilot 代码审查 Pull Request GitHub Universe 2026 代理协作
- GitHub Universe 2026 的代理协作能力怎样影响代码审查流程
- 264浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 820次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 811次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 903次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 873次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 695次使用
-
- 接口返回的数据和数据库不一致怎么办?按数据生命周期排查
- 2026-06-27 398浏览
-
- 关于golangtest缓存问题
- 2023-01-01 298浏览
-
- Go语言基于HTTP的内存缓存服务的实现
- 2022-12-24 388浏览
-
- 使用Go实现健壮的内存型缓存的方法
- 2022-12-29 420浏览
-
- Go singleflight 怎么合并同一请求:缓存失效时别让 500 个请求一起回源
- 2026-07-17 109浏览

