Wallet-Stealer Payloads in Package Ecosystems: The Most Boring Attack Pattern in 2026

Written by the Rafter Team

If you sort the supply-chain compromises Rafter has covered this quarter by payload type, the largest single bucket is "scan the host for crypto wallet files and exfiltrate them." Not infostealers in the broader sense, not credential harvesters, not even C2 implants. Specifically: read ~/.config/Solana, ~/Library/Application Support/Exodus, the browser extension storage paths for MetaMask and Phantom, the keystore directories for desktop wallets, and ship them to an HTTPS endpoint.
The payload is uninteresting. The repeatability is the story.
A wallet-stealer payload is the floor of supply-chain attack quality, not the ceiling. If your build pipeline does not catch the floor, every more-sophisticated payload will pass through it the same way. Audit your dependency surface against the same baseline that catches the wallet stealers — postinstall hook awareness, hash-pinning, install-time sandboxing.
The shape of a wallet stealer
Across recent disclosures — the Trivy/TeamPCP compromise, the Mercor LiteLLM incident, and the Canisterworm / ClawHavoc cluster — the wallet-stealer subset of the payload bestiary looks roughly identical.
The mechanics are stock:
- Postinstall trigger. The package's
package.json(orsetup.py, or containerENTRYPOINT) executes a script during install. The script is the payload, not the package's actual code. This is so common that "postinstall hooks as a bug class" is its own pattern post. - Platform-conditional payload. A first-stage script checks
os.platform()and downloads the OS-specific binary. macOS gets a Mach-O, Linux gets an ELF, Windows gets a PE. The conditional structure exists to keep the visible code small in the npm tarball; the actual wallet logic is in the downloaded binary. - Wallet path enumeration. The downloaded binary walks a hardcoded list of paths — usually 30-50 entries covering the major wallet apps and browser extensions across OSes. For each path that exists, it tars the directory.
- HTTPS exfil to attacker-controlled endpoint. Sometimes wrapped in a transient subdomain (
f4j3.attacker.example.com), sometimes routed through a benign-looking pastebin or storage service.
That is the entire attack. No persistence beyond install. No lateral movement. No second-stage download (beyond the binary). The cleverness is in not being clever — the simpler the payload, the harder it is to write a high-confidence detection signature.
Why "boring" is a feature
A wallet stealer monetizes on the order of hours. The attacker compromises a package, ships the payload, and starts cashing out as soon as installs propagate. Compared to the multi-week, multi-stage operations against named enterprises that get most of the press, a wallet stealer is a small business — and small businesses are easier to scale.
The supply-chain economics favor this pattern in three ways:
- The payload is reusable. The same wallet-enumeration binary works against the next compromised package, then the one after. No bespoke development per target.
- The signature is fragmented. Every campaign uses slightly different infrastructure, slightly different paths, slightly different filenames. By the time a defender writes a detection, the payload has moved.
- The victim is invisible. Most wallet theft is never publicly attributed to a specific package compromise. The user notices the funds are gone; they do not necessarily realize it traces to a dependency they installed three weeks ago.
That last point is the structural defender problem. The feedback loop between "a compromised package was published" and "we have specific user-loss data tied to it" is broken. Without that loop, the defensive case for tightening the dependency-install pipeline is harder to make at the budget table.
What actually defends against this
The defenses that catch wallet stealers are the same defenses that catch every other postinstall-payload attack. The fact that the payload is "boring" does not make the defenses easier — it makes them measurable, because the floor is well-defined.
Pin and verify dependency hashes. A wallet-stealer payload almost always lives in a freshly-pushed version of a previously-trusted package. Hash pinning (--require-hashes on pip, package-lock.json with subresource verification on npm, content-addressed digests on container images) means the new compromised version cannot be installed without an explicit hash update.
Disable postinstall hooks by default. npm install --ignore-scripts is one flag. The flag is a small price compared to the blast radius of every postinstall payload from the past year. If you have a build that genuinely requires a postinstall hook, allowlist that package; don't allow every package to run arbitrary code at install time.
Sandbox the install. Run dependency installs inside a container without network egress to anywhere other than your package registry. The wallet-stealer's second-stage download breaks. The HTTPS exfil breaks. The platform-conditional binary download breaks. This is the most effective single control and the least-adopted.
Monitor your dependency tree for transitive surprises. Half the wallet-stealer compromises this quarter were in packages that you did not install directly — they came in as transitive dependencies of something you did install. The transitive dependency risks post covers the framing.
The Rafter angle
rafter run catches a class of the precondition: dependency declarations with postinstall hooks, unpinned versions, dependencies pulled from unverified sources. rafter secrets . will not stop a wallet stealer, but it will stop the inverse — your own wallet keys or API keys being committed to a public repo, which is the supply-side of the same economy. Neither replaces the operational hygiene above. They give you a place where the hygiene is enforced on every PR rather than every quarter.
The wallet-stealer pattern is not interesting because the payloads are interesting. It is interesting because it shows you the floor of the supply-chain threat. Every defense calibration that misses the floor misses everything stacked on top of it.