The Rust Security Response Team was notified that Miri stores all environment variables to target/
, allowing secrets to persist in caches.
While not necessary a vulnerability in and of itself, when paired with GitHub Actions caching behavior, it is possible for this to expose secrets to PRs.
Overview
GitHub Actions makes it possible to cache directories between runs. Typical setups allow CI runs on main
(and other branches) to write to cache, and PRs can only read from cache (preventing cache poisoning). Rust projects tend to speed up CI by caching binaries built by cargo install
and sometimes the contents of target/
.
PR CI can be triggered by anyone who can open PRs on your repository. GitHub requires maintainer approval for the first PR, but future PRs will rerun CI on every push. Anyone who has previously landed a change can trigger a CI run extracting information from cached target/
and then cover their tracks by pushing a second commit to the PR.
GitHub sometimes hides overwritten commits in its UI, making this kind of attack harder to detect. CI run logs and overwritten commits are also deleted after a few months.
When cargo miri
is invoked, Miri needs to retain build-relevant environment variables between runs1. The current code to do so achieves this by storing all environment variables to target/
. This, of course, persists when target/
is cached.
If your environment contained secrets, these can now be accessed by PRs via the cache.
Our fix
Our short term fix for this is to make Miri only preserve CARGO_*
environment variables (excepting CARGO_*_TOKEN
) and OUT_DIR
. In the longer term, Miri and cargo may figure out better ways to inform Miri of the relevant list of environment variables. Note that this patch may not be available on nightly yet.
We also performed an ecosystem scan of GitHub repositories and identified 1 repository with this issue and 7 repositories that do not appear to be vulnerable but should be cautious anyway. We have reached out to those maintainers.
Am I affected?
It is likely that our scan was imperfect, so we recommend you check your own GitHub Actions setups if you run Miri.
You are vulnerable if:
- You run
cargo miri
in CI - The step that runs
cargo miri
has access to secrets as an environment variable:- By being passed in to the step itself as an environment variable
- By being set in
env
for the workflow - By being passed in to a previous step that persists it in the environment somehow
- The workflow being used caches the
target
directory, usually done viaactions/cache
orswatinem/rust-cache
- The cache is accessible to PRs (common and often the intended use case)
Possible quick fixes include:
- Disabling cache for that job.
- Scoping secrets to steps in that job that do not call Miri.
- Temporarily disabling Miri.
Once done, please clear the cache. Consider rotating any secrets that might have leaked.
The Miri release in the upcoming nightly (2026-09-22) will no longer have this problem.
Even if you do not run Miri, ensure jobs that can write to public caches do not have access to secrets. Many tools do not have special handling for secrets, and assume the entire environment can be written to the filesystem.
Threat model
We consider it bad practice to have a cache that can easily be tainted by secrets.
If caching target/
, it is worth making sure that the inputs to processes that create target/
(anything invoking cargo
) do not have secrets available. It is generally rare for standard cargo
build/test subcommands to need any secrets or tokens2, so this is mostly a matter of being careful about having secrets exposed as environment variables to the entire job.
Cargo/Miri/Rust does not guarantee that environment variables will be safe from being copied into target/
. While we are treating this as a security issue and patching it out of an abundance of caution, this is not something you should rely on in general. Beyond official Rust tooling, it is possible for build scripts to be doing things that lead to the environment being stored in compilation artifacts.
Acknowledgements
Thanks to Predrag Gruevski of OpenAI for reporting this issue to us. Furthermore, the ecosystem scan was performed using Codex access and credits donated by OpenAI, which we also thank them for.
Issue triage and remediation was performed by Manish Goregaokar, Ralf Jung, Ben Kimock, Weihang Lo, Jacob Finkelman, Walter Pearce, Josh Stone, and Mark Rousskov.
Facts Only
* The Rust Security Response Team identified a behavior where Miri stores all environment variables in the target/ directory.
* This behavior allows secrets to persist in caches.
* When combined with GitHub Actions caching, secrets can be exposed to Pull Requests.
* GitHub Actions allows main branches to write to caches and PRs to read from them.
* Predrag Gruevski of OpenAI reported the issue.
* OpenAI provided Codex access and credits for an ecosystem scan of GitHub repositories.
* The scan identified one vulnerable repository and seven repositories that should be cautious.
* A short-term fix limits preserved variables to OUTDIR and CARGO* variables, excluding CARGO*TOKEN.
* The fixed version of Miri is scheduled for the nightly release on 2026-09-22.
* Triage and remediation involved Manish Goregaokar, Ralf Jung, Ben Kimock, Weihang Lo, Jacob Finkelman, Walter Pearce, Josh Stone, and Mark Rousskov.
Executive Summary
Miri, a tool used in the Rust ecosystem, previously stored all environment variables within the target/ directory to ensure build-relevant data persisted between runs. In environments using GitHub Actions, where the target/ directory is frequently cached to optimize CI speed, this creates a security risk. Because PRs can often read from caches created by the main branch, any secrets stored as environment variables during a main-branch run could be extracted by a PR contributor. Attackers could potentially hide these actions by pushing subsequent commits to overwrite the evidence in the GitHub UI.
To mitigate this, the Rust Security Response Team is transitioning Miri to only preserve specific CARGO* variables and the OUTDIR, explicitly excluding tokens. Users currently running cargo miri in CI with cached target directories and active secrets are advised to disable caching for those jobs, scope secrets more narrowly, or rotate potentially leaked credentials. While a formal patch is arriving in the 2026-09-22 nightly release, the team emphasizes that the broader risk of environment variables being written to disk by various build tools persists beyond this specific fix.
Full Take
The strongest version of this narrative is a transparent, proactive disclosure by a security team to prevent a specific class of "secret leakage" in CI/CD pipelines. It acknowledges that while the behavior is not a vulnerability in isolation, it becomes one when integrated into the specific permission model of GitHub Actions.
The pattern here is SKEPTICAL MODE. The communication is straightforward and technical. There is no evidence of fear-mongering or vendor-pushing; rather, it is a warning about the fragility of environment-based secret management.
Patterns detected: none
The root cause is a common architectural friction: the tension between "state persistence" (needed for speed/caching) and "least privilege" (needed for security). This echoes a historical pattern in software engineering where convenience-oriented defaults—such as dumping the entire environment to a file—create silent failure modes that only become apparent when the software is deployed in multi-tenant or shared-trust environments like GitHub.
The implication is a reduction in the perceived safety of "secret" environment variables. It highlights that the boundary between volatile memory (RAM) and persistent storage (disk/cache) is often porous. The cost is borne by developers who must now audit their CI pipelines, while the benefit is a more robust, "secure-by-default" tooling chain.
Bridge Questions:
1. If build tools cannot be trusted to handle environment variables safely, what is the superior alternative for passing build-time configuration?
2. To what extent does the reliance on third-party CI caching (like actions/cache) create systemic risks that tool maintainers cannot realistically patch?
Counterstrike Scan: A coordinated campaign would use this to sow distrust in the Rust compiler or GitHub's infrastructure to push a competing language or CI platform. The actual content is a targeted technical fix and does not match this pattern.
Sentinel — Human
The text appears to be a technically detailed security advisory, exhibiting strong human organizational structure and domain-specific precision, rather than purely synthetic generation.
