Announcing the crates.io Cooldown Proxy — mitigating supply-chain attacks through delayed availability
A free public Cargo sparse-index proxy that withholds newly-published crate versions for 1–30 days, reducing exposure to supply-chain attacks.
Published by the Human-life Information Platforms Institute (Menhera.org)
April 2026
TL;DR
We have launched a public Cargo sparse-index proxy that withholds newly-published crate versions for a configurable period (1–30 days), giving the community time to detect and respond to malicious releases before they reach your build.
Point Cargo at it:
[registries.menhera-cooldown]
index = "sparse+https://index.crates.menhera.org/3d/"
[registry]
default = "menhera-cooldown"
[source.crates-io]
replace-with = "menhera-cooldown"
[source.menhera-cooldown]
registry = "sparse+https://index.crates.menhera.org/3d/"
[alias]
publish-crates-io = [
"publish",
"--config", "registry.default = \"crates-io\"",
]
~/.cargo/config.toml
Run this, pasting your crates.io's token as usual (we don't intercept them):
cargo loginReplace 3d with any integer 1d–30d for your preferred cooldown window. That's it. No account required, no rate limit for reasonable use, faithful to upstream in every other respect.
Use cargo publish-crates-io instead of cargo publish.
What is this?
https://index.crates.menhera.org/ is a filtering mirror of the crates.io sparse index. It speaks the same protocol Cargo uses to talk to https://index.crates.io/, so Cargo doesn't know or care that it's talking to a proxy.
The one thing the proxy does differently from upstream: it hides crate versions that were published recently. "Recently" is whatever window you choose via the URL prefix — /1d/ through /30d/, counting calendar days from publication.
Crate tarballs are served directly by crates.io's own CDN (static.crates.io). The proxy only filters index metadata; it does not touch the actual crate content. Checksums, signatures, and everything else are identical to what you'd get without the proxy — just with a moving cutoff on version visibility.
Why is this needed?
Rust's package ecosystem, like every language ecosystem, is vulnerable to supply-chain attacks: a malicious actor publishes a compromised version of a crate (often via a compromised maintainer account, a typo-squatting name, or a legitimate-looking update to a popular package), and anyone who runs cargo update within the vulnerability window pulls in the attack.
The standard defenses fall short in ways that matter:
cargo auditand RustSec advisories are reactive: they flag known-bad versions. If a compromised version hasn't been identified yet,cargo auditwon't catch it.- Pinned versions in
Cargo.tomlprotect your direct dependencies but offer nothing against transitive ones, which are where most attacks land because developers don't visually review them. Cargo.lockonly helps if you don't update it — and a team that never runscargo updateaccumulates unpatched bugs and advisories.- Manual review of every new version of every transitive dependency is not a realistic defense for any team building real software.
What the Rust ecosystem has empirically observed is that malicious crate releases are typically identified and yanked within hours to a few days — by security researchers, by maintainers of the affected crate, by users who notice unusual behavior, by automated scanners. The window of maximum danger is right after publication, before the community has had time to look.
This proxy closes that window by making recently-published versions invisible to Cargo for a chosen cooldown period. Your build simply can't resolve to a version that's too new. By the time a version ages into visibility through the proxy, it has been exposed to the community's attention for the full cooldown window.
This isn't a novel idea. Similar "quarantine" or "cooldown" patterns exist in other ecosystems — npm has been discussing it for years, some enterprise Python mirrors offer it, and Debian's stable/testing/unstable structure is an analogous idea at a much longer timescale. What has been missing in Rust is a zero-configuration, publicly-available implementation that any project can adopt with a three-line change to .cargo/config.toml. That is what this service provides.
What this protects against, and what it does not
Protects against:
- Compromised-maintainer attacks that are identified and yanked within the cooldown window.
- Typo-squatting crates that are taken down within the cooldown window.
- Malicious dependencies introduced by maintainer-turnover or account-takeover scenarios, as long as the compromise becomes publicly known within the window.
- Accidentally broken releases that a maintainer yanks within the window.
- Most of the crate supply-chain incidents that have historically been seen in the Rust ecosystem.
Does not protect against:
- Patient attackers willing to sit on a compromised release longer than your cooldown window.
- Attacks on crates that are never publicly identified as compromised.
- Attacks via build scripts or procedural macros in crates that were already in your
Cargo.lockbefore being compromised. (The proxy affects resolution; it does not re-evaluate crates already resolved.) - Attacks on the proxy itself, or on crates.io upstream. We do our best on the former; the latter is out of scope.
- Attacks on git dependencies or path dependencies. The proxy only filters crates-io-sourced packages.
In other words: this is a probabilistic defense that buys you time against attacks detected by the community. It is not a replacement for cargo audit, code review, cargo-deny, cargo-vet, signed commits, or any of the other tools in your supply-chain toolbox. It complements them.
Think of it like a quarantine period on imported goods: most contraband gets caught, but nothing is perfect, and the defense works best in combination with other measures.
How to use it
Quick start
Add to your project's .cargo/config.toml:
[registries.menhera-cooldown]
index = "sparse+https://index.crates.menhera.org/3d/"
[registry]
default = "menhera-cooldown"
[source.crates-io]
replace-with = "menhera-cooldown"
[source.menhera-cooldown]
registry = "sparse+https://index.crates.menhera.org/3d/"
[alias]
publish-crates-io = [
"publish",
"--config", "registry.default = \"crates-io\"",
]~/.cargo/config.toml
Replace 3d with any integer 1d–30d for your preferred cooldown window.
On each machine, authenticate once using your crates.io API token:
cargo login(Paste the same token you use for cargo login against crates.io. The proxy directs API operations — including authentication — to crates.io, not intercepting them, but tells Cargo to directly use crates.io for API operations.)
Normal cargo commands (build, update, install, search) now route through the proxy by default, with index reads filtered by the cooldown policy and API operations/tarball downloads going directly to crates.io. publish needs a special attention: use cargo publish-crates-io instead.
A note on authentication: When you run cargo login after configuring the proxy as your default registry, Cargo consults the proxy's config.json to determine where to send the token. Our config.json is a faithful pass-through of upstream crates.io's, meaning tokens are sent directly to https://crates.io — our infrastructure never sees your authentication token. You can verify this at any time:
curl -s https://index.crates.menhera.org/7d/config.jsonThe "api" field should read "https://crates.io". If it ever doesn't, that is a signal to stop trusting the proxy and report it.
Choosing a cooldown window
There is no single right answer; pick based on your risk tolerance:
- 1d–3d: Minimal friction, catches most automated scanner detections. Suitable for projects that want some defense without meaningfully slowing access to new crate versions.
- 7d (our default recommendation): Balances safety and freshness. Almost all publicly-identified compromised releases are yanked within this window. Catches accidental broken releases that maintainers fix within a week.
- 14d–30d: Maximum safety. Suitable for security-critical applications, infrastructure projects, nonprofits, and organizations where the cost of a supply-chain incident greatly exceeds the cost of waiting for new dependency versions.
You can also use different windows in different projects or CI environments. A sensible pattern: 3d or 7d for regular development, 14d or 30d for release builds and production pipelines.
Verifying it works
Once configured, cargo update should still work, but newly-published versions won't appear. To spot-check:
# A version published yesterday should not resolve under a 7d cooldown
# but should resolve under a 1d cooldown.
curl -s "https://index.crates.menhera.org/7d/<prefix>/<crate>" | wc -l
curl -s "https://index.crates.menhera.org/1d/<prefix>/<crate>" | wc -l
The 1-day response will have more lines (more versions visible) than the 7-day response if any versions of that crate have been published in between.
Using with CI
In CI, override via environment variable or a CI-specific config file:
export CARGO_REGISTRIES_MENHERA_COOLDOWN_PROTOCOL=sparse
# ... and mount a .cargo/config.toml pointing at the proxy
Or bake it into your CI image's cargo config directly.
Falling back to upstream
If the proxy is ever unavailable (we aim for very high uptime, but nothing is perfect), you can temporarily revert to upstream by passing --registry crates-io to Cargo. Your builds will proceed against index.crates.io directly, without cooldown. For production-critical pipelines, consider whether your policy prefers "fail closed" (no builds during proxy downtime) or "fail open" (builds proceed without cooldown during downtime).
How it works, technically
The proxy is a small Rust service running on Fastly's edge compute platform. On each request:
- It parses the URL to determine the cooldown window (
/Nd/) and the upstream index path. - It fetches the corresponding response from
index.crates.io(heavily edge-cached). - It consults a timestamp database to look up when each version in the response was published.
- It removes lines corresponding to versions younger than the cooldown window.
- It returns the filtered response to Cargo.
The timestamp database is populated from the official crates.io database dumps, which are published daily. We re-ingest on a fixed schedule and additionally poll for new publications on a shorter interval so that the "is this version too young" decision is always made against near-real-time data.
For config.json (the file that tells Cargo where to download tarballs), we pass through upstream's response unchanged. This means crate tarballs are fetched directly from static.crates.io, not through us — we are strictly a metadata filter, not a bytes-in-motion proxy. This minimizes our attack surface and means a compromise of the proxy cannot substitute malicious crate content (since Cargo verifies checksums against the upstream index and downloads from upstream's CDN).
What we can and cannot do as operator
What we could hypothetically do, being transparent about this:
- Hide specific versions beyond the cooldown rules (e.g. pretend a crate version doesn't exist). Cargo would then not resolve to it.
- Delay or fail requests for specific crates or user agents.
What we fundamentally cannot do:
- Serve modified crate tarballs. Cargo verifies checksums, and the checksums we serve in index metadata come directly from upstream. Any tampering would produce a mismatch and Cargo would reject the download.
- See the contents of your private code or builds. The proxy only sees requests for index metadata, the same requests Cargo sends to
index.crates.iotoday. - Associate requests with individuals. The proxy is unauthenticated and we do not log identifying information beyond what's necessary for operational troubleshooting (see "Privacy" below).
To verify our honest behavior, you can diff the filtered response from our proxy against the raw response from upstream:
diff <(curl -s https://index.crates.menhera.org/7d/se/rd/serde) \
<(curl -s https://index.crates.io/se/rd/serde)
The only differences should be the removal of version lines whose created_at is within the cooldown window.
Privacy
- The service is unauthenticated. No account creation, no API keys, no cookies.
- We do not log IP addresses beyond what CDN-level rate limiting requires (transient, not retained).
- We do not log the user-agent string, query patterns, or any personally-identifiable information.
- Aggregate traffic metrics (request counts per endpoint, cache hit rates, error rates) are retained for operational purposes.
- We do not share data with third parties.
If privacy-preserving access is important to you, the proxy works equally well from Tor. Menhera operates its own Tor infrastructure on AS63806 and supports this use case.
Operational details
Availability: We aim for high availability but availability depends on Fastly.
Support: This is a public-benefit service provided by a nonprofit. We cannot offer SLA-backed commercial support. For bug reports, integration questions, or incident notifications, reach us at the contacts listed at the bottom of this page.
Data freshness: Cooldown decisions are made against a timestamp database refreshed from the crates.io DB dump daily, supplemented by shorter-interval polling for new releases. In the unlikely event the proxy's view of "when was version X published" is briefly stale, the effect is that a version becomes visible slightly later than strictly required, never earlier.
crates.io relations: We have nothing to do with crates.io team. This service complies with crates.io's acceptable-use guidance: just being a proxy, live queries are heavily cached at our edge, and we pass through any User-Agent as-is. We are grateful to the crates.io team for operating the world-class piece of infrastructure this service sits on top of.
Why a Japanese nonprofit is running this
Menhera.org (the Human-life Information Platforms Institute, 一般社団法人生活情報基盤研究機構) is a Japan-incorporated nonprofit whose mission is to empower individuals with more freedoms by designing IT systems, infrastructure, protocols, and more. We operate AS63806 as a research autonomous system of the Internet, with a focus on privacy and protocol work.
Supply-chain attacks on open-source ecosystems are a collective-action problem: every individual project and every individual developer benefits from a healthier ecosystem, but the defenses that would help most (quarantine windows, community review, cryptographic attestation) require infrastructure that no single project wants to run. Running this proxy as a public good fits our mission: we already operate infrastructure, we already care about the ecosystem, and the marginal cost of providing this service to the world is small compared to its aggregate benefit.
We are not funded by, affiliated with, or operating on behalf of any cloud vendor, any government, or any other entity. We are a small Japanese nonprofit running infrastructure we believe should exist.
The service is provided free of charge for public use. If your organization uses it at scale and wants to support its continued operation, donations are welcome via our website. We may offer paid SLA-backed tiers in the future for organizations that require contractual commitments; the free tier will remain free.
Suggestions, bug reports, and feature requests are welcome. This is open infrastructure and we want it to serve the community's actual needs.
FAQ
Is this a replacement for crates.io?
No. It is a transparent read-only filter in front of crates.io. All crate data originates from and is ultimately served by crates.io. If crates.io is unavailable, we are also unavailable.
Does this work for private registries?
Not currently. The proxy is specifically for crates.io. If you maintain a private registry and want similar cooldown semantics, the proxy code will be available for self-hosting.
Will this slow down cargo build?
No noticeable difference. The proxy is edge-cached aggressively, so almost all requests are served from a CDN point of presence near you, often faster than upstream index.crates.io for users geographically distant from the upstream's primary regions.
Can I pick a cooldown longer than 30 days?
Not currently via the URL scheme. If you have a concrete use case for longer cooldowns, let us know; we're open to extending the range.
What happens to versions that get yanked during the cooldown window?
They never become visible through the proxy. Yanked versions are treated the same way as too-young versions for the purposes of our filter. This is actually a side benefit: you're protected not just against not-yet-discovered attacks but also against accidentally-broken releases that maintainers later yank.
Can I self-host this?
The source is released under Apache-2.0 OR MPL-2.0. If you want to run your own instance (for private registries, for custom policies, for regulatory reasons, or because you prefer not to depend on a third party), you will be able to.
Who is the maintainer?
Menhera.org. Direct contact information is at the bottom of this page.
I just published a crate and my own project can't see it — why?
The cooldown applies uniformly: any version younger than the window is invisible, including versions you just published. If you need immediate access to a just-published crate (e.g., to test it in a dependent project), either temporarily lower your cooldown window to 1d, or override the default registry for that specific invocation (cargo build --registry crates-io).
I cannot do cargo publish.
Do cargo publish-crates-io if you use our snippets, or use the following snippet:
CARGO_REGISTRY_DEFAULT=crates-io cargo publish --config 'source.menhera-cooldown.registry = "sparse+https://index.crates.menhera.org/0d/"'0d bypasses cooldown
Source code and contributions
The proxy's source code is as follows. Issues, pull requests, and security reports are welcome.
https://github.com/menhera-org/index-crates-menhera
Contact
- Website: https://www.menhera.org/
- Email:
itops %AT% menhera.ad.jp
The Human-life Information Platforms Institute is a Japan-incorporated nonprofit (一般社団法人生活情報基盤研究機構). This service is provided as a public good in alignment with the Institute's mission. No warranty is expressed or implied. Use at your own discretion.
This post was initially drafted with Claude Opus 4.7 (an LLM) but it incorporates substantial manual review and changes. The author takes full responsibility on this content.