June 7, 2026
The Day Rust’s Time Utilities Started Stealing Secrets
A storytelling case study on malicious crates, typosquatting, and developer-secret exfiltration
Ajay Kumar
10 min read
A storytelling case study on malicious crates, typosquatting, and developer-secret exfiltration
A Rust developer opens a terminal late at night.
The feature is simple: add a small utility crate, clean up some logging, run tests, push the branch, let CI do the rest.
Nothing looks dangerous.
The crate name sounds boring. Helpful, even.
time-sync
time_calibrator
chrono_anchor
These are not names that trigger fear. They sound like small utilities written by someone who needed to solve the same annoying problem you have: synchronize time, normalize timestamps, make a service behave properly across environments.
So the developer types:
[dependencies]
time-sync = "..."[dependencies]
time-sync = "..."Cargo resolves the package. The build succeeds. Tests pass. CI turns green.
But somewhere between "dependency added" and "pipeline completed," a different story begins.
The package is not just handling time. It is looking for secrets.
And in modern software, secrets are everywhere: .env files, API keys, database URLs, cloud tokens, wallet keys, private keys, CI variables, local test credentials, staging credentials that accidentally still work in production.
This is the uncomfortable lesson from a series of malicious Rust crates discovered across 2025 and 2026: the attack no longer has to break your memory safety. It only has to win your trust.
Rust did not fail. Trust failed.
Rust gives developers powerful guarantees around memory safety and concurrency. That is one reason backend, systems, blockchain, data infrastructure, and security-conscious teams love it.
But dependency trust is a different problem.
A Rust crate can be memory-safe and still malicious. It can compile cleanly, pass tests, expose a useful API, and still quietly read local files or call out to a remote server. The compiler can protect you from many classes of bugs, but it cannot automatically know whether a dependency's business logic is honest.
That is where the real attack surface lives: not in unsafe, but in developer habit.
We search. We install. We skim the README. We trust the name. We trust the ecosystem. We trust that someone else would have noticed.
The attackers behind these crates understood that.
Chapter 1: The fake timekeepers
The first pattern looks almost innocent: time-related crates.
According to RustSec and Socket reporting, crates such as time_calibrator, time_calibrators, dnp3times, time-sync, and chrono_anchor attempted to exfiltrate .env files or similar secrets. Several of them impersonated or referenced the legitimacy of timeapi.io, while attacker-controlled infrastructure used a lookalike domain such as timeapis[.]io.
This is a clever choice of disguise.
Time APIs are boring. Nobody expects drama from a package that sounds like it merely synchronizes timestamps. In backend systems, time is everywhere: token expiry, cache invalidation, distributed tracing, scheduled jobs, rate limits, event ordering, payment settlement, cron workers, audit logs.
A developer does not think, "This package might steal my .env."
They think, "Finally, I found a crate that solves this small issue."
That is the attacker's advantage.
Socket assessed the time-utility crates as part of a coordinated campaign based on repeated code patterns, shared infrastructure, and similar exfiltration logic. The campaign's goal was not to crash systems or install noisy ransomware; it was quieter: collect secrets from developer environments and CI workflows.
The important nuance: many of these crates were removed quickly and some RustSec advisories state there was no evidence of real usage or actual downloads. For example, time_calibrators was reportedly removed about three hours after publication, dnp3times about six hours after publication, and time-sync about fifty minutes after publication. chrono_anchor, however, was published on March 4, 2026 and removed about six days later, according to RustSec.
That speed matters.
It shows the Rust security response process worked.
But it also shows something else: attackers are probing the ecosystem repeatedly. Even failed packages teach them what gets detected, how quickly registries respond, which names look believable, and which developer niches might be easier to target next.
A failed attack today can become a refined campaign tomorrow.
Chapter 2: The logger that listened too much
The second story is more dangerous because it reached more machines.
In September 2025, the crates.io team disclosed two malicious crates: faster_log and async_println. These crates impersonated legitimate logging functionality and used typosquatting to look trustworthy. faster_log had been downloaded 7,181 times and async_println 1,243 times before removal, according to the official Rust blog.
The disguise was strong because the crates were not obviously broken.
They copied working logging code. They had useful behavior. They looked like something a developer might add during a refactor, a CLI project, a backend service, or a quick experiment.
That is what makes this kind of malware scary: it does not always announce itself through failure.
It works.
But during runtime, when a project using the crate was run or tested, the malicious payload searched file contents for Ethereum private keys, Solana private keys, and arbitrary byte-array patterns. The official crates.io disclosure says the exfiltration went to a Cloudflare Workers endpoint disguised as a Solana RPC pool.
Socket's write-up adds that the crates impersonated the legitimate fast_log library and included working logging code as cover, while scanning source files for wallet-related secrets before sending matches through HTTP POST to the attacker-controlled endpoint.
This is the key lesson:
A malicious dependency does not need to run during build.rs to be dangerous.
Many developers focus heavily on build scripts, proc macros, and install-time execution. Those are real risks. But faster_log and async_println showed another path: execute during normal runtime. Run the malware when the developer runs tests. Run it when the service starts locally. Run it when CI executes integration tests. Run it when a CLI tool is invoked.
That is a brutal attack path because it hides inside normal development.
From the developer's point of view, nothing strange happens. The app starts. Logs appear. Tests complete.
Meanwhile, the dependency has already done the one thing the attacker wanted.
Chapter 3: The crate that looked clean because the malware lived elsewhere
The finch-rust and sha-rust case shows a different trick: hide the real payload in a dependency.
In December 2025, the crates.io team disclosed finch-rust and sha-rust. The package finch-rust tried to create confusion with the existing finch crate, while adding a dependency on sha-rust, which performed data exfiltration. The official Rust blog says finch-rust had one version, was downloaded 28 times, and used sha-rust as a dependency; sha-rust had eight versions and 153 downloads.
This pattern is especially relevant for backend engineers.
When reviewing a suspicious dependency, many developers inspect only the top-level crate. They look at the README, the repository, maybe a few source files.
But modern dependency attacks often hide in the transitive graph.
The visible crate can look almost normal. The dangerous code lives one level deeper.
Socket described finch-rust as a malware loader that appeared to mimic the legitimate finch package while secretly pulling in sha-rust, where the credential-stealing logic lived. The attack also used an unpinned dependency strategy so downstream users could receive newer malicious payload versions automatically within the same compatible range.
That is a very important supply-chain lesson.
In Rust, your risk is not only:
[dependencies]
some_crate = "1.2.3"[dependencies]
some_crate = "1.2.3"Your risk is also everything that crate brings with it.
A professional dependency review must include:
cargo treecargo treeNot just:
cargo add somethingcargo add somethingThe top-level crate is the front door. The transitive dependency graph is the whole building.
Chapter 4: The Web3 trap
The fourth story targets a very specific developer psychology: crypto urgency.
Web3 developers often work with private keys, wallet integrations, RPC providers, signing flows, smart contracts, local dev wallets, and testnet/mainnet configuration. That makes them valuable targets.
In December 2025, the crates.io team disclosed evm-units and uniswap-utils. The official Rust blog said both crates downloaded a payload likely attempting to steal cryptocurrency. evm-units had 13 versions published in April 2025 and 7,257 downloads; uniswap-utils had 14 versions, 7,441 downloads, and used evm-units as a dependency.
Socket's analysis described evm-units as a package disguised as an EVM version helper. It reportedly downloaded OS-specific payloads, wrote them to a temporary directory, and executed them silently, while appearing to return an Ethereum version number so the victim would not notice anything unusual.
That is the perfect criminal product design.
Give the developer the output they expected.
Do the malicious work in the background.
In this case, the attacker did not rely only on a typo. The crate name matched the target audience. evm-units sounds like something a blockchain developer might plausibly need. uniswap-utils sounds like a helper library in the DeFi ecosystem.
The attack blended into the workflow.
And that is what mature supply-chain attacks do: they do not look random. They speak the language of the victim.
For a Java developer, the bait might be a fake Spring helper. For a Kubernetes engineer, it might be a fake Helm utility. For a Rust Web3 developer, it might be an EVM helper. For a data engineer, it might be a fake connector.
The attacker does not need everyone.
They only need the right developer with the right secrets.
Chapter 5: The Polymarket credential hunt
The rpc-check case shows persistence.
RustSec reported that rpc-check was part of an ongoing campaign to typosquat crates in the polymarket-client-sdk ecosystem and attempt credential exfiltration. The crate had six versions published from February 20, 2026 onward, with no evidence of actual usage and no dependent crates on crates.io. RustSec also advised Polymarket developers to review dependencies carefully because the attacker appeared motivated to steal Polymarket credentials.
This is important even though the advisory says there was no evidence of actual usage.
Security teams should not measure risk only by successful downloads.
Repeated attempts in one ecosystem signal attacker interest. If one package fails, another name may follow. If one typo is caught, a different typo may be tried. If a direct imitation is removed, the attacker may switch to a helper crate, plugin crate, SDK wrapper, or "examples" package.
The first malicious crate may be only reconnaissance.
The second may be improved.
The third may be the one that works.
Why these attacks work
These incidents are different, but the attacker playbook is consistent.
First, choose a believable name.
Not every malicious package needs to impersonate a famous crate. Sometimes it is enough to sound useful: time sync, logging, EVM helpers, RPC checks, SDK utilities.
Second, make the package functional.
A broken malicious crate is suspicious. A working malicious crate is dangerous because it reduces friction. Developers continue using it because it appears to solve the original problem.
Third, target secret-rich environments.
Local developer machines and CI pipelines often contain more secrets than people realize. .env files, cloud keys, wallet keys, package tokens, database URLs, GitHub tokens, and staging credentials may all exist near source code.
Fourth, avoid noisy behavior.
Many of these attacks were designed for exfiltration, not destruction. The goal was not to break the build. The goal was to quietly collect valuable material before anyone noticed.
Fifth, exploit transitive trust.
finch-rust depending on sha-rust is a perfect example. The package you choose may not be the package that hurts you. The payload may sit one layer deeper.
The backend engineering lesson
For backend engineers, the biggest lesson is this:
Dependency security is production security.
A crate added casually during local development can become part of a production image, a CI pipeline, an internal tool, or a release workflow. Once a dependency enters the graph, it can travel through environments faster than anyone expects.
This is why "small utility crates" deserve scrutiny.
A crate that handles logging can read files. A crate that handles time can make network calls. A crate that handles SDK authentication may sit near credentials. A crate that handles Web3 utilities may sit near wallet keys.
You should not treat dependency review as bureaucracy. You should treat it as part of system design.
When you design a production Rust backend, ask:
What code do we run? Who published it? How old is the crate? Does the repository exist? Does the crate name resemble a more popular package? Does it perform filesystem access? Does it perform network access? Does it execute OS-specific payloads? Does it have unexpected transitive dependencies? Does CI allow outbound traffic freely? Would we notice if a dependency posted secrets to an external domain?
Most teams cannot manually audit every line of every dependency. But they can build friction around dangerous behavior.
A practical Rust supply-chain checklist
Before adding a new crate, especially a low-download or newly published one:
cargo tree
cargo tree -i suspicious_crate_name
cargo auditcargo tree
cargo tree -i suspicious_crate_name
cargo auditCheck the crate's repository. If the README claims a GitHub repo exists, open it. Look at commit history, issues, maintainers, tags, and whether the repository actually matches the published crate.
Check the name carefully. Typosquatting often lives in tiny differences:
fast_log vs faster_log
finch vs finch-rust
timeapi.io vs timeapis[.]io
sdk vs sdks
client vs clientsfast_log vs faster_log
finch vs finch-rust
timeapi.io vs timeapis[.]io
sdk vs sdks
client vs clientsReview transitive dependencies:
cargo tree --duplicates
cargo tree --edges normal,build,devcargo tree --duplicates
cargo tree --edges normal,build,devFor high-risk projects, consider network restrictions in CI. Most unit tests do not need arbitrary outbound internet access. If a dependency suddenly calls an unknown endpoint during tests, that should be visible.
For secret-heavy projects, never keep real production secrets in .env files on developer machines. Use short-lived credentials, scoped tokens, local-only test credentials, and separate cloud roles.
If you discover one of these crates in your history, do not only remove the dependency. Treat the environment as potentially exposed. Rotate relevant secrets, review CI logs, check outbound network logs if available, and inspect whether the dependency ever ran locally or in CI.
What makes this scary for Rust
Rust's ecosystem has earned trust because of its engineering culture. Developers often associate Rust with correctness, safety, and serious systems work.
Attackers borrow that trust.
They know that Rust developers are building valuable things: blockchain infrastructure, backend services, cryptographic tools, developer platforms, cloud-native systems, data pipelines, and security-sensitive infrastructure.
That makes crates.io a high-value target.
The crates.io team has been responding quickly. In February 2026, the crates.io team also updated its malicious-crate notification policy, saying it would not publish a blog post for every malicious crate because many advisories had no evidence of real-world usage; instead, RustSec advisories would continue to be published for removed malware, while higher-impact cases could still receive broader notification.
That policy makes sense.
But it also means developers cannot rely only on headline visibility.
Some malicious crates will not become viral news. They may only appear as RustSec advisories. They may have no famous blog post. They may not trend on Reddit. They may not reach your LinkedIn feed.
Your process has to catch what the news cycle misses.
The uncomfortable truth
The modern attacker does not always need a zero-day.
Sometimes the attacker only needs a name that looks right.
A crate that sounds boring.
A README that looks normal.
A function that returns the expected value.
A dependency that nobody checks.
A CI runner with outbound internet.
A .env file sitting in the project root.
That is enough.
The malicious Rust crates discussed here are not just isolated incidents. They are signals. They show where attackers believe developer workflows are weak: package discovery, dependency review, transitive trust, local secrets, CI isolation, and Web3 credential handling.
The solution is not paranoia.
The solution is engineering discipline.
Use Rust for its strengths. Use Cargo with caution. Review dependency graphs. Restrict secrets. Watch outbound traffic. Treat new packages as code you are inviting into your house.
Because sometimes the crate that promises to calibrate time is really there to steal the keys before the clock runs out.
Want to Learn Production Rust with Real Projects and CVE Case Studies?
I have created a complete Rust Backend Engineering Learning Material for developers who want to master Rust for real backend systems.
It includes production-grade Rust projects, Axum, Tokio, PostgreSQL, Docker, testing, deployment, and deep Rust CVE case studies like this one.
You can check it here:
👉 Get the Complete Rust Backend Engineering Bundle here: https://tobiweissmann.gumroad.com/l/gnuvxu