MALFEX: An npm Package Stayed Malicious for Fourteen Months With No Advisory

Written by the Rafter Team

As of October 6, 2026.
When an advisory feed has nothing on a package, it tells you no one has written one up.
It does not tell you the package is clean.
The npm package function-flag has been malicious since July 2025, and as of October 1 no advisory named it.
What happened
On September 30, CloudSEK tied a set of npm packages to one operator and named the campaign MALFEX. On October 5, Checkmarx published its own analysis of the same packages. Both describe one operator publishing to npm since August 2023: twelve packages, eight of them malicious and four harmless ones that serve as cover.
The operator signs the work.
The name appears in five npm publisher accounts (malfexkkj, malfex_user, malfexteste2 through malfexteste4), in the git author email of the payload repository, and in the stealer's decryption key, malfexteam2027.
CloudSEK found the same key named in an Amazon Inspector advisory for one package, without a link to the operator.
The malware runs on Windows only. Checkmarx describes three delivery paths that share an operator but not infrastructure, so blocking one leaves the others working.
Three ways in
A remote access trojan.
Three packages (tlxbnhd, tldriver, mxdriver) run preinstall and postinstall scripts that download a Windows program disguised as a PNG.
It unpacks a signed AutoIt3 interpreter and an encrypted script, which load Overlord, an open-source remote access trojan written in Go.
Checkmarx lists its capabilities: screen capture, keylogging, clipboard capture, file search, remote shell access, and a hidden desktop the operator can use without the user seeing it.
Overlord has no hard-coded server. It can read encrypted memos the operator posts in Solana transactions and use them as its server list, so changing servers takes one new transaction and taking a server down does not break the scheme. CloudSEK says its recovered build has the Solana resolver wired in as live strings; Checkmarx says the build it analyzed had no Solana address configured and showed no command traffic in testing.
A stealer.
native-runner, img-to-native and cdn-img-fetch run when they are loaded, with no install hook.
They pull a PNG from a GitHub repository, decrypt an executable hidden after the image data, and fetch a 64 MB Node.js stealer that Checkmarx and CloudSEK call movinlike.
It takes Discord tokens, browser cookies and saved logins, Telegram sessions and crypto wallet data, and posts them to a Discord webhook.
A downloader in function-flag.
This is the part that lasted.
In version 1.7.3, the postinstall script calls the package's ASCII-art function with the font name "Bloody," and that value triggers a hidden routine that downloads node.exe and runs it with its window hidden.
The malicious lines are padded with spaces so they sit past the right edge of a typical editor, and the routine is wrapped in an empty catch, so a failed download leaves no error.
After publishing a malicious 4.0.0, the operator published a newer malicious build under the lower number 1.7.3.
function-color contains no payload; it installs function-flag as a dependency.
Fourteen months without an advisory
Between September 22 and 30, OSV malware advisories went out for six of the eight malicious packages, most of them from Amazon Inspector.
Five packages left the registry: the three trojan loaders were unpublished, and npm seized img-to-native and native-runner.
The gaps are where the risk sat:
function-flag, which CloudSEK calls "continuously malicious since 18 July 2025," had no advisory. Checkmarx counts 37,419 of the campaign's 40,767 downloads on it.function-color, its wrapper, had no advisory.cdn-img-fetchstayed installable after npm seizedimg-to-native, the package that loads it. Its advisory, published September 30, lists versions 1.0.0 and 1.0.1 and leaves out the malicious 1.0.2 and 1.0.3.
As of October 1, Checkmarx found all three still installable.
Any check that asks only "is there an advisory for this version?" passed them.
A release-age cooldown passes function-flag too: npm's registry metadata dates version 1.7.3 to August 2025.
Download counts measure reach, not infections. Checkmarx notes that no legitimate or widely used package depends on any MALFEX package, so exposure is limited to machines that installed these names directly.
What to do now
- Search lockfiles and installed trees for all eight names.
function-flag,function-color,cdn-img-fetch,img-to-native,native-runner,tlxbnhd,tldriverandmxdriver. A lockfile can keep a malicious version pinned after the registry removes it. Checkmarx's report lists the commands. - Block all eight in your registry proxy or allowlist. A registry takedown does not purge copies in private registries, proxies and caches; purge those too.
- Treat a Windows machine that installed one as compromised. Isolate it, look for the trojan's persistence as Checkmarx and CloudSEK describe it (a fake
ScopeSmart Technologies Incfolder under%LOCALAPPDATA%and a scheduled task named\Maiden), and rotate Discord, browser-saved and other credentials from a clean machine. Deletingnode_modulesdoes not undo a payload that already ran. - Block the payload hosts. Both reports publish the URLs, IP addresses and the Discord webhook.
- Do not rely on advisory feeds alone. Pair feeds with review of new dependencies and of what their install scripts do.
- Run installs with scripts off where you can.
npm install --ignore-scripts, orignore-scripts=truein.npmrc, stops the preinstall and postinstall paths. It does not stop the stealer chain, which runs when the package is loaded, so it narrows the problem rather than closing it.
The advisory is the lagging signal
MALFEX runs on install-time code, the common primitive in this year's npm attacks.
What stands out is how long one package ran in plain view.
function-flag sat on the public registry for more than a year with a payload hidden behind a font name and a run of spaces, and the advisory system that most tooling relies on did not name it.
A campaign that steals wallets and tokens needs only a few installs to pay. The defense that fits does not wait for the advisory. It is a short list of packages someone chose on purpose, installed with scripts off unless one needs them.