wshu.net npm Credential-Stealer Campaign

discovered 2026-06-23

ACTIVELY ONGOING single-actor npm supply chain campaign, named for the wshu.net publisher infrastructure that ties its members together; @apexcraft/nano-key is the convicted ROOT/lineage member (secondary identifier). Amazon Inspector security research (Chi Tran, 2026-06-19) independently documented the SAME cluster as 'Operation Friday Harvest' (same 13 wshu.net scopes, same <scope>-<6char>@wshu.net burner pattern, same ~260-282KB obfuscator.io payload, same dual-trigger) - independent corroboration that raises confidence on the cluster to HIGH/confirmed. Confirmed members now total 15 packages across 13 throwaway scopes seeded on 2026-06-04; THREE of those scopes (@zynkit, @frostnode, @gleamkit) each hold a payload-free scope-reservation probe stub. Amazon Inspector's fuller version enumeration shows 64 malicious versions across the cluster (broader ranges than SafeDep statically pulled - e.g. @apexcraft/nano-key 1.2.4/1.2.5/1.3.2-1.3.8, @glitchpad/throttler 2.1.1/2.2.1-2.2.4, @nullzero/urlcat 1.4.0-1.4.3, @tinyfox/shapecheck 0.7.4/0.8.5-0.8.8, @zynkit/jwtbytes 0.4.3/0.5.1-0.5.4). Each payload package masquerades as a small developer utility (JWT/byte helper, retry wrapper, shape validator, throttler, logger, hex parser, env validator, datetime lib, RxJS poll operator) but ships a 259-282KB javascript-obfuscator payload blob executed via a postinstall hook. CORRECTED PAYLOAD BEHAVIOR (Amazon Inspector dynamic analysis SUPERSEDES the earlier static hypothesis): the obfuscated JS blob is a DOWNLOADER/LOADER, not a self-contained browser-credential stealer. It spawns a detached child process behind env-var guards, downloads a ~10.6MB Rust-compiled binary from GitHub Releases (github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/{linux,mac,win.js}), and executes it. The Rust binary is the actual infostealer: 30+ crypto wallets (MetaMask, Phantom, Trust Wallet, Solflare, Keplr, Ledger, Trezor, ...), browser credentials (Chrome/Brave/Firefox/Edge passwords/cookies/history/autofill/cards), cloud tokens (AWS/GCP/Azure/Kubernetes), SSH keys, Discord tokens + Telegram session data, developer creds (npm tokens/.env/.npmrc/GitHub PAT/PyPI tokens), and DB client connection strings (DBeaver/pgAdmin/MongoDB Compass). Persistence: a systemd USER service masquerading as a benign daemon (observed colord, haveged) at ~/.local/bin/<daemon> + ~/.config/systemd/user/<daemon>.service. Exfil C2: the Windows variant uses the Telegram Bot API (api.telegram.org, 149.154.166.110); Linux/macOS variants POST multipart/form-data over HTTP (minreq lib), gated behind anti-VM checks (Windows is NOT gated). The EARLIER static hypothesis - that the payload was itself the convicted @apexcraft/nano-key Chromium browser-credential stealer (Cookies/Login Data -> aes-256-gcm decrypt -> HTTPS exfil) - is now SUPERSEDED by this confirmed downloader->Rust-infostealer chain; browser-credential theft survives only as one capability of the Rust second stage, not the whole payload. SafeDep's independently-verified FIRST-STAGE observations stand: obfuscator.io RC4+base64 string decoder, the guarded runPrepare()/onInstall() wrapper auto-fired via require.main===module, dynamic require to keep module names out of the static graph, and byte-identical/near-identical compiled blobs. The STRONGER pivot is the GitHub delivery account angelmaybeth21-oss (created 2026-06-03; repo 'test' now removed but account live) and secondary smilingdusty233 (created 2026-05-31) - not the shared disposable wshu.net email. The DURABLE campaign fingerprint is the shared obfuscator.io template plus 5 build clusters (A-E) keyed by string-array function name and re-entrancy guard tag (A=_0xe119/__EE9863E13F_TAG: @apexcraft,@briskforge,@chunklab; B=_0x36b9/__7D0A53D40B_TAG: @glitchpad,@nullzero,@lazyutil; C=_0x175f/__38CC632841_TAG: @petitcode,@tinyfox,@thymelab,@zynkit; D=_0x5da4/__70FE9F7AB6_TAG: @bytemend; E=_0x15fd/__4C6BA78C7C_TAG: @frostnode) - members in the same cluster share the same obfuscator seed, which explains SafeDep's byte-identical-blob finding. CORRECTION: wshu.net is a PUBLIC DISPOSABLE-EMAIL provider (on disposable-email-domains, fakefilter, MISP warninglists, authgear's free-email list, and in unrelated apps' temp-mail signup logs), so the wshu.net domain ALONE is a NOISY pivot, NOT a unique attacker-owned indicator. Latest dist-tag of every payload package was republished with empty scripts to evade casual npm view metadata checks while the payload remains in mid-versions. @nullzero/urlcat (publisher [email protected]) is a same-actor member whose flagged version 1.4.2 was UNPUBLISHED before SafeDep static inspection. The earlier noon-contracts npm package (2026-05-10, publisher [email protected]) shares ONLY the disposable-email provider, not payload or code; that link is WEAKENED - treat it as a low/medium-confidence lead.

Objective

Compromise developer and CI hosts at scale: install-time obfuscated npm packages download and run a Rust-compiled infostealer that harvests crypto wallets, browser credentials, cloud/SSH/developer tokens, and chat-app sessions, exfiltrated via Telegram (Windows) or HTTP multipart (Linux/macOS).

Related campaigns

Packages

Indicators

Techniques

Read the full analysis →