Rust Fixes Miri Bug That Leaked CI Secrets to PRs
Security / news
Rust Fixes Miri Bug That Leaked CI Secrets to PRs
A same-day patch closed the hole, but the Rust team won't say which repository was actually exposed.
Rust's Miri interpreter wrote every build-time environment variable, secrets included, into a target/ directory that GitHub Actions then cached on any repository running cargo miri in continuous integration (provided that repository also cached that path). Any pull request could read it, the Rust Security Response Team said Sept. 21.
Predrag Gruevski, an engineer at OpenAI, reported the flaw to the team that same day. The team's writeup says it identified one repository with the exposure and seven more that "do not appear to be vulnerable but should be cautious anyway," without naming any of them. "We have reached out to those maintainers," the post says, leaving the affected project unidentified to anyone reading it.
How a merged pull request became a skeleton key
Miri needs a handful of environment variables to carry over from a build step to a run step, and its existing code did that by dumping the entire process environment into target/ rather than filtering for the ones it actually needed. Any CI job that ran cargo miri with secrets set as environment variables, on a workflow that cached target/ to speed up builds, put those secrets in the cache.
GitHub Actions normally lets a pull request read a cache written by a trusted branch but not write to one, a protection meant to stop an attacker from poisoning the cache itself. The Rust team's post says that protection does not help here: "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 requires a maintainer to approve a contributor's first pull request, but every pull request after that reruns CI automatically on each push, with no further approval required.
A same-day fix, no CVE attached
Rust maintainer RalfJung merged the fix as pull request 5337 the day the team learned of the bug, two commits that make Miri preserve only variables prefixed CARGO_*, excluding any named CARGO_*_TOKEN, plus OUT_DIR, instead of the full environment. It shipped in the nightly build dated Sept. 22. The team assigned no CVE identifier and described the change as a short-term patch, saying Miri and Cargo "may figure out better ways to inform Miri of the relevant list of environment variables" later on.
| Date | Event |
|---|---|
| Sept. 21, 2026 | Predrag Gruevski reports the exposure to the Rust Security Response Team |
| Sept. 21, 2026 | RalfJung merges the fix as pull request 5337 |
| Sept. 22, 2026 | The patched nightly build ships |
| Sept. 22, 2026 | Unsloth audits its 26 repositories against the disclosure |
What one downstream project found when it went looking
Unsloth, which publishes open-weight model fine-tuning tools on GitHub as unslothai, audited all 26 of its repositories against what its own pull request calls "the 2026-09-21 Rust disclosure, where cargo miri wrote the entire process environment to a file under target/." Engineer Daniel Hanchen wrote in the merged pull request that the audit found no active exposure there, because Unsloth's workflows lacked the specific combination of a cached, PR-readable target/ directory and secrets in that job's environment, the same combination that made the Rust-identified repository vulnerable.
Hanchen's team made three changes anyway: it disabled Rust cache saves in its release workflows, added guards against credentials leaking through Hugging Face's home-directory cache, and rewrote how a Docker token gets passed so it no longer appears as a command-line argument. None of those three problems is the Miri bug itself. The audit simply went looking for the same shape of mistake once it had a reason to check, the kind of downstream review that only happens after a fix ships before anyone explains why it mattered, which is exactly the order events ran in here too.
What still isn't public
Rust's post does not say how the one confirmed-vulnerable repository was exposed in practice, whether any secret there was actually read by an attacker rather than merely exposed, or whether it has been rotated. That silence sits alongside GitHub's own recent effort to rebuild Copilot's runtime in Rust, a reminder that the platform running the vulnerable caches is also, increasingly, a major consumer of the language whose tooling produced this one.
Maintainers running cargo miri in CI with secrets in the job's environment and a target/ cache that pull requests can read are the ones who need to check now. Everyone else's exposure through this specific bug ended when the nightly shipped Sept. 22.
Sources
More in Security
- 01Go Team Weighs Turning Off Default MPTCP After Linux FlawThe Go Security Team called a default change premature on Oct. 29, while commenters on golang/go issue 82717 split over keeping multipath TCP on.
- 02Anthropic's Claude Exploit Chains Hit Five Targets, Each With LimitsThe Frontier Red Team's Oct. 27 post covers Chrome, Safari, Android, Windows and Linux, but only the Chrome and Linux results reach code execution.
- 03A Tampered Claude Code Extension Sat in Cursor's Marketplace for 11 Hours and Left an SSH Key BehindVersions 2.1.312 and 2.1.313 carried a 7,386-byte loader that plants an attacker key and a reverse tunnel. Uninstalling the extension does not remove either.
- 04Ivanti Connect Secure Zero-Day Chain Gave Root on a Patched VPN, and the Integrity Checker Misses ItVolexity dates exploitation to October 3, ten days before Ivanti's advisory; the root escalation step has no CVE and no fix in the sources reviewed.