← All publications
Threat Report July 2026

What We Caught: July 2026

A month of supply-chain malware on npm — five operations, 33 malicious releases, caught from the live changes feed.

July 2026 6 pages 9 min read
By codelake Research

This month codelake confirmed and reported five distinct supply-chain malware operations on npm, spanning 33 malicious package releases. All were caught from the live changes feed — within the window between publication and takedown — and several were novel, not present in OSV or GHSA at detection. Every finding here is structurally confirmed (not an AI-only verdict), was reported to the registry and filed to the OpenSSF Malicious Packages database, and all indicators are defanged. Three patterns recur: the install hook is still the whole attack; payloads escalate and operators cover their tracks; and novel-first-catch, plus an archive that survives the operator's cleanup, is the moat.

One package walked from a recon beacon, through a credential harvester, to a full reverse shell across five releases — then the operator unpublished the entire package to erase it from npm. We had already archived it.

The numbers

5
distinct malware operations confirmed and reported this month
codelake, Jul 2026
33
malicious package releases across the five operations
codelake advisories
25
packages in one coordinated @wagni_bot crypto-typosquat campaign
CLR-2026-3000..3024
5
releases of one package escalating beacon → harvester → reverse shell
date-format-utils-xz
1.0.4
recovered from a registry mirror after the operator unpublished the package
codelake
100%
fired from an install lifecycle hook — --ignore-scripts would have stopped all five
codelake analysis

Inside this report

The largest operation of the month was a single coordinated campaign of 25 packages under one npm scope, typosquatting popular crypto-wallet and Web3 SDKs (MetaMask, Binance, Solana, Jupiter, Orca, OpenSea, Polymarket, Hyperliquid, Polygon, BSC, Ethereum, Web3 toolkits and more).

The tell was structural, not nominal: the payload was byte-identical across all 25 packages at each version, and every one exfiltrated to the same Telegram bot token — the fingerprint of a single automated actor spraying a scope. On install, each package harvested SSH private keys (~/.ssh/id_rsa), local crypto-wallet files and .env secrets and shipped them to the operator's Telegram bot as the dead-drop.

Because the packages were structurally identical, they were reviewed and reported as a set — filed CLR-2026-3000 through 3024, reported to npm for takedown, and submitted to the OpenSSF Malicious Packages database with codelake credited as finder. Defensive indicators: SSH-key + wallet + .env reads in a lifecycle script; a single Telegram bot token shared across many same-scope packages; typosquats of wallet/Web3 SDK names.

Details → full advisory →

The most instructive single case was a fake date-formatting utility whose own source called itself, in a Chinese comment, "disguised as a normal date formatting tool." Its decoy index.js exported a working formatDate(); the malice was in its postinstall hook, and it escalated across every one of its five releases. 1.0.0 was a recon beacon; 1.0.1–1.0.3 probed cloud instance-metadata (Alibaba, AWS/GCP, Tencent) and dumped the full environment to a C2, which migrated from the domain zhijiujiu[.]cn to the bare IP 8.135.48[.]40 to dodge DNS blocking; 1.0.4 escalated to a full reverse shell — net.connect to 8.135.48[.]40:4444 spawning /bin/sh, with bash /dev/tcp and python3 pty fallbacks.

The progression — beacon → metadata/credential harvester → interactive remote code execution — is a compact case study in how a single package matures once it survives its first releases. Then the operator unpublished the entire package, all five versions, to erase the trail. codelake had already archived 1.0.0–1.0.3; version 1.0.4 was recovered from a public registry mirror that still cached it, after npm returned 404. This is exactly why an independent, retain-everything archive matters: the registry's record is the operator's to delete; ours is not.

Filed as CLR-2026-3039 (novel; not in OSV at detection). The 1.0.3→1.0.4 reverse-shell escalation was independently flagged by codelake's predecessor-version differ as a top poison-injection candidate. Defensive indicators: C2 zhijiujiu[.]cn and 8.135.48[.]40 (:80 harvest, :4444 shell); cloud-metadata probes to 169.254.169.254 / 100.100.100.200 / metadata.tencentyun.com.

Details → full advisory →

supplyhub shipped a clean 1.0.0, then poisoned 1.0.2 with a postinstall hook that read the developer's SSH private key (~/.ssh/id_rsa) and process environment (/proc/self/environ — where CI, cloud and npm tokens live), gathered host identity, and POSTed the lot to a hard-coded webhook.site dead-drop.

The clean-then-poison shape is the classic way to launder trust: the first release looks fine to a casual reviewer, the payload lands in a later one. Filed as CLR-2026-3038 (novel). Defensive indicators: ~/.ssh/id_rsa + /proc/self/environ reads in postinstall; exfil to a webhook.site endpoint; a benign earlier version and a poisoned later one.

Details → full advisory →

A fake Gutenberg/Tailwind block package whose postinstall was a download-execute dropper: it fetched a second-stage payload from a raw public IP (172.94.9[.]157), which ran hidden PowerShell and exfiltrated via Telegram.

Raw-IP download targets in an install script are a high-signal discriminator — legitimate installer packages fetch from vendor domains, GitHub or CDNs, not bare IPs. Filed as CLR-2026-3037. Defensive indicators: a postinstall that downloads from a raw IP and executes it; hidden PowerShell; Telegram exfil.

Details → full advisory →

The most novel operation of the month was faust-cont, an npm package whose index.js is a benign "cli tool" decoy while its install hook (node install.js) does the work. On Windows it writes and launches a hidden PowerShell stage that bootstraps a runtime toolchain — scoop, then winget, then Deno — and finally runs deno run -A against a second-stage payload fetched from a raw public IP (172.94.9[.]157) over plain HTTP, granting the remote module all Deno permissions (filesystem, network, environment, subprocess). Per the loader's own comments the staged payload sets up autorun persistence and runs a main payload.

The novelty is the execution vector. Instead of the usual curl | sh or a Node payload, it installs Deno and runs a remote URL directly — so no payload file is written to disk by the dropper itself, only Deno's URL cache is populated, which side-steps Node-centric endpoint tooling. We named and documented this technique as Deno-as-LOLBin. The payload host 172.94.9[.]157 is the same raw IP used by tailwind-gutenberg-block-zero above, tying the two operations to a common operator; faust-cont adds the Deno twist.

Filed as CLR-2026-3040 (novel; not in OSV at detection), the package was already unpublished from npm by analysis time — the artifact survives only in the codelake archive. In OSV, codelake is the sole finder: Amazon Inspector, OpenSSF and SafeDep did not report it. Defensive indicators: an install hook that writes hidden PowerShell and bootstraps scoop/winget/Deno; deno run -A against a bare IP over HTTP; alert on unexpected Deno installs appearing at package-install time.

Details → full advisory →

Install-time is the battlefield. All five fire from a lifecycle hook on npm install. The single most effective consumer mitigation — --ignore-scripts in CI, plus pinned, reviewed dependencies — would have stopped every one.

Credentials are the prize. SSH keys, .env secrets, cloud instance-metadata credentials, wallet files: the payloads converge on the things that unlock other systems. An install-time compromise is a credential compromise. And operators clean up — the date-format-utils-xz unpublish shows the registry's record is deletable by the attacker; an independent, retain-everything corpus, and mirror recovery when needed, is what preserves the evidence.

Structural confirmation before naming names. Every finding here was confirmed by deterministic on-box analysis — the exact reads, the exact C2, the exact hook — never an AI verdict alone, and only then published. All were reported to npm and filed to the OpenSSF Malicious Packages database with codelake credited as finder. Full technical advisories, with hashes and per-version indicators, are at research.codelake.dev/advisories.

Data appendix · key indicators

IndicatorValueAs ofPrimary source
@wagni_bot campaign 25 packages · wallet/SSH/.env stealer Jul 2026 CLR-2026-3000..3024 →
date-format-utils-xz 5 releases · harvester → reverse shell Jul 2026 CLR-2026-3039 →
supplyhub 1 release · SSH-key & credential stealer Jul 2026 CLR-2026-3038 →
tailwind-gutenberg-block-zero 1 release · download-execute dropper Jul 2026 CLR-2026-3037 →
faust-cont 1 release · Deno-as-LOLBin dropper (novel) Jul 2026 CLR-2026-3040 →

Registry counts overlap across indices and must not be summed. Survey figures reflect the cited sample, not the global population.

Selected sources

codelake structural malware analysis (live npm changes feed). All findings reported to npm and filed to the OpenSSF Malicious Packages database with codelake credited as finder. Full advisories with hashes and indicators: research.codelake.dev/advisories. Indicators in this report are defanged.

Keep reading

More from codelake Research