NPM Campaign Uses 700+ Malicious Packages to Deliver Cross-Platform Malware

Summary
Researchers analyzed an npm campaign involving more than 700 malicious packages that execute malware when imported. The downloader targets Windows, Linux, and macOS, uses HTTPS and DNS TXT records for payload delivery, and can establish macOS persistence.
Key points
- The campaign’s packages masquerade as SDKs; importing one can trigger infection without an npm lifecycle script.
- The downloader targets Windows, Linux, and macOS, retrieving payloads through rotating HTTPS hosts or Base64-encoded DNS TXT records under wel1[.]ru.
- The macOS payload can download another stage, evade analysis tools, and establish persistence with a disguised LaunchAgent.
- The researchers tracked 788 packages and analyzed Linux and macOS payloads; the final beacon remains unavailable for analysis.
- Investigate package installation and import history, DNS and proxy logs, dropped files, processes, and macOS persistence artifacts.
- For confirmed execution, treat the host as potentially compromised, rotate accessible credentials and secrets, and rebuild from a known-good state where appropriate.
Article Details
- Attack Vectors
- Malicious NPM packages execute their downloader when imported with require(), without using preinstall or postinstall lifecycle scripts.
- The downloader retrieves platform-specific payloads over HTTPS from attacker-controlled Cloudflare Workers hosts, with DNS TXT records under wel1.ru as a fallback delivery channel.
- Downloaded payloads are written to temporary paths and launched in detached processes. The macOS payload retrieves an additional beacon, installs a LaunchAgent for persistence, and includes anti-analysis checks.
- Defensive Notes
- Identify campaign packages in installed dependencies, lockfiles, package-manager caches, build logs, SBOMs, and deployed applications; determine whether they were imported, since removing the dependency alone may be insufficient.
- Review DNS logs for TXT lookups under wel1.ru, proxy logs for the listed Workers hosts, and endpoint telemetry for the described dropped-file, process, and macOS LaunchAgent indicators.
- Rotate credentials accessible to affected developer workstations or CI runners, including npm and GitHub tokens, cloud credentials, signing keys, and deployment secrets; rebuild affected systems from a known-good state where appropriate.
- Treat confirmed execution as a potential host compromise because the final macOS beacon was unavailable for analysis.
Indicators of compromise
| Type | Indicator | Context |
|---|---|---|
| DOMAIN | dl[.]wel1[.]ru | Additional DNS TXT payload-delivery domain embedded in the macOS loader. |
| DOMAIN | ext[.]dl[.]wel1[.]ru | DNS TXT payload-delivery domain used for Linux ARM64. |
| DOMAIN | net[.]dl[.]wel1[.]ru | DNS TXT payload-delivery domain used for Windows. |
| DOMAIN | oob-worker[.]cf102-baf[.]workers[.]dev | Attacker-controlled host used to deliver payloads over HTTPS. |
| DOMAIN | oob-worker[.]cf103-070[.]workers[.]dev | Attacker-controlled host used to deliver payloads over HTTPS. |
| DOMAIN | oob-worker[.]cf99-9b3[.]workers[.]dev | Attacker-controlled host used to deliver payloads over HTTPS. |
| DOMAIN | package-proxy[.]cf11oobworker[.]workers[.]dev | Embedded payload-proxy host in the macOS loader. |
| DOMAIN | package-proxy[.]cf5oobworker[.]workers[.]dev | Embedded payload-proxy host in the macOS loader. |
| DOMAIN | package-proxy[.]cf6oobworker[.]workers[.]dev | Embedded payload-proxy host in the macOS loader. |
| DOMAIN | package-proxy[.]cf7oobworker[.]workers[.]dev | Embedded payload-proxy host in the macOS loader. |
| DOMAIN | package-proxy[.]cf8oobworker[.]workers[.]dev | Embedded payload-proxy host in the macOS loader. |
| DOMAIN | pkg[.]dl[.]wel1[.]ru | DNS TXT payload-delivery domain used for macOS. |
| DOMAIN | sdk[.]dl[.]wel1[.]ru | DNS TXT payload-delivery domain used for Linux x64. |
| SHA256 | 0fc30f82e1fa5e51a6c0c43f3ed7f13592ea731cb331e43a4d085df60a4db8b6 | SHA-256 hash listed for the malicious package's README.md. |
| SHA256 | 7e486657f30594afda379b97030252a09a19fe8055e25c9e371544f59bd8e9e3 | SHA-256 hash of the analyzed Linux x86-64 native payload. |
| SHA256 | 94ef6b1c4a9d31f78f446d053048bcef34fd88f4376a1a46f7f777a9e9c83a29 | SHA-256 hash listed for the malicious package's _helpers.js downloader. |
| SHA256 | a3e2ffb440b779d30da3ff282affd649731088e8570df7b1aa72742d995b782c | SHA-256 hash listed for the package's telemetry.js file containing a duplicate downloader design. |
| SHA256 | b74c5675725911c62091bdf40714df760cc2af7a88360d21065f4e1c878aa8f0 | SHA-256 hash listed for the malicious package's index.js. |
| SHA256 | c214746c74cae8ece8bdaf69aa05da4db6ce013f9e77452d1eed1a002fd9ba00 | SHA-256 hash of the analyzed universal macOS native payload. |
| SHA256 | e2650e9aa2f924433ba422857b22ee7c5996b5ad306f3f903283f6a13e248935 | SHA-256 hash listed for the malicious package's package.json. |
MITRE ATT&CK
T1059.003 · Windows Command ShellOn Windows, the downloaded executable is launched with cmd.exe /c start /b.T1059.004 · Unix ShellOn Linux and macOS, the downloaded executable is launched through /bin/sh -c.T1059.007 · JavaScriptThe malicious package uses JavaScript in _helpers.js to run its downloader when imported.T1105 · Ingress Tool TransferThe downloader retrieves payloads over HTTPS or reconstructs them from DNS TXT chunks.T1497.001 · System ChecksThe macOS payload checks system memory with hw.memsize as a likely sandbox heuristic.T1497.003 · Time Based ChecksThe macOS payload looks for debuggers, instrumentation, packet-capture tools, and VMware artifacts.T1547.011 · Plist ModificationThe macOS payload creates and loads a user LaunchAgent plist to run the executable at login.
Products
Cloudflare WorkersThe downloader supports Windows, Linux, and macOS. It rotates through three Cloudflare Workers hosts for its primary payload delivery and falls back to reconstructing the payload from DNS TXT records hosted undernpmOver the course of 48 hours a threat actor has published more than 700 malicious packages to the NPM registry. These packages appear to use AI slop squatted, or randomly generated typo-squatting package names, but allNPM registryOver the course of 48 hours a threat actor has published more than 700 malicious packages to the NPM registry. These packages appear to use AI slop squatted, or randomly generated typo-squatting package names, but all
Tools
launchctllaunchctl load -w '<path>/com.apple.windowserver.helper.plist' 2>/dev/nulllibcurlIt uses libcurl for HTTPS and libresolv for direct DNS queries. Its imports include curl_easy_perform, res_9_query, fork, setsid, execl, chmod, ptrace, and sysctlbyname. Together, these support HTTPS and DNS delivery,node-fetchThe request is forced over IPv4, times out after 15 seconds, and uses node-fetch/2.6 as its User-Agent. A response is accepted only when the server returns HTTP 200 and more than 1,000 bytes.UPXLinux x86-64 ELF, statically linked and UPX-packed
