TechScriptsNepal
Blog

MALFEX: eight malicious npm packages, three payloads, and why --ignore-scripts isn't enough

TechScripts Nepal · Kathmandu · October 26, 2026 · 6 min read

In early October, researchers at CloudSEK and Checkmarx published details of MALFEX, a long-running campaign on the npm registry. One operator, active since August 2023, published twelve packages, eight of which have been flagged as malicious. Together they were downloaded about 40,767 times. Those are registry downloads, not confirmed infections, but the campaign is a useful case study in how modern npm malware gets past the defenses developers rely on.

Every payload targets Windows. macOS and Linux machines are not affected, though that is no reason to skip the checks below if your team includes Windows developers or Windows CI runners.

The packages

  • function-flag (postinstall downloader): 37,419 lifetime downloads
  • cdn-img-fetch (stealer chain): 643
  • img-to-native (stealer chain): 967
  • native-runner (stealer chain): 872
  • function-color (pulls in function-flag as a dependency): 300
  • mxdriver, tlxbnhd, tldriver (Overlord RAT loaders): 289, 139 and 138

As of Checkmarx's September 29 snapshot, two packages (img-to-native and native-runner) had been seized by npm and three loaders had been unpublished, but function-flag, function-color, and cdn-img-fetch were still installable, and two of them had no advisory at all. Sources differ on exactly which remained live afterwards, which is itself the point: an advisory feed alone would have missed some of this.

Two delivery methods, one gap

The interesting part of MALFEX is that it uses both of the ways npm malware typically runs.

Install-time scripts. The three Overlord loaders use obfuscated preinstall and postinstall scripts, so the malicious code runs the moment someone runs npm install. function-flag also uses a postinstall script, and function-color triggers it by depending on it.

Import-time execution. The stealer chain (native-runner, img-to-native, cdn-img-fetch) has no install hook at all. The malicious code runs when the package is required. img-to-native does nothing visible itself except require cdn-img-fetch, which triggers the payload.

That distinction matters because a common defense is installing with --ignore-scripts, or using a package manager configured to skip install scripts. That blocks the first method completely and does nothing against the second. Other 2026 incidents show the same pattern: the compromise of the popular node-ipc package in May, for example, shipped a credential-stealing payload that also ran when the module was loaded rather than through install hooks.

What the three payloads do

Overlord RAT. A file served with an image content type is actually an IExpress archive containing a signed AutoIt interpreter and an encrypted script. The script decrypts Overlord, a Go-based remote access trojan with screen capture, keylogging, clipboard monitoring, file search, a remote shell, and a hidden virtual desktop. Checkmarx's code analysis (not observed at runtime) indicates it injects itself into a signed Windows binary. Persistence is a scheduled task named \Maiden. Overlord has no hardcoded command-and-control address. It reads encrypted server addresses from Solana blockchain transactions, so the operator can change where infected machines connect without touching any infrastructure that a takedown could reach.

The movinlike stealer. An AES-encrypted payload hidden after PNG image data is decrypted into a Go downloader, which fetches a Node.js stealer of roughly 64 MB. It targets Discord tokens and account data, browser cookies and saved logins, Telegram session data, and cryptocurrency wallets. The loot is zipped, split into 25 MB chunks, and posted to a hardcoded Discord webhook.

The function-flag downloader. Each malicious version pulls a different payload from a different URL. Version 1.7.3 fetched a node.exe into the user's %APPDATA% folder. That host is now offline, so this payload hasn't been recovered, and researchers have not established a link between function-flag and the movinlike stealer.

What's still uncertain

It's worth being straightforward about the limits of what's known. The download counts measure how many times the registry served the files, which includes mirrors, scanners, and CI caches. No one has published a count of compromised machines. Overlord's process injection was inferred from reading the code, not observed. The analyzed Overlord build had no configured server address, so no command-and-control traffic was seen during testing.

How to check your own projects

  1. Search the dependency tree. Run npm ls --all and look for the eight package names, which catches transitive dependencies you never chose directly.
  2. Search your lockfiles. Check package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, and yarn.lock. Removed malicious versions can stay pinned in a lockfile and keep being installed from caches.
  3. On Windows machines, look for indicators: a \Maiden scheduled task, node_runtime_helper.exe under %APPDATA%\Microsoft\Windows, a stray node.exe in %APPDATA%, and a directory named ScopeSmart.
  4. Review proxy and DNS logs for unfamiliar download hosts, including Discord attachment-style URLs and raw IP addresses.
  5. Block the packages at your registry proxy and purge them from private registries and caches.

If a machine looks affected, isolate it and preserve evidence first. Then, from a clean system, rotate credentials for anything used on that host (Discord, browser-saved accounts, cloud and CI tokens), end Telegram sessions, and move any cryptocurrency to fresh wallets. For a developer machine, assume source-control and cloud credentials are in scope too.

Reducing exposure going forward

  • Treat new dependencies as a decision, not a convenience. Check the age, maintainers, and download history of a package before adding it, and be suspicious of tiny utility packages with odd names doing something an existing library already does.
  • Pin and review. Commit lockfiles, install with npm ci in CI, and review dependency changes in pull requests the way you review code.
  • Don't run installs with more access than they need. Developer laptops and CI runners often hold cloud keys, SSH keys, and publishing tokens. Scope those so a bad package can't reach everything.
  • Layer your defenses. Skipping install scripts helps, but as MALFEX shows it doesn't cover code that runs on import. Registry scanning, egress filtering, and least-privilege credentials each close part of the gap.

Supply-chain risk is hard for small teams because nobody owns it. It sits between developers who just want to ship and security people who can't read every dependency. A technical partner who reviews your dependency policy and CI setup once, and leaves you with rules your team can follow, can close a lot of that gap. That's work we do at TechScripts Nepal, and our posts on why 2026 is a record year for breaches and open-source maintainers closing the door on outside contributions cover the wider context behind it.