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.
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:
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
Approximate number of downloads
Table 1: Malicious npm package names, version numbers, and approximate number of downloads.
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.
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.
The following sections examine NodeCordRAT’s capabilities, including its host fingerprinting, C2 communication, and data exfiltration methods.
Before establishing C2 communication, NodeCordRAT performs host fingerprinting to generate a unique identifier for each compromised machine, in the following format: - (e.g., win32-c5a3f1b4).
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:
Shell command Execution
Executes arbitrary shell commands such as dir , ls , or complex scripts using Node.js’s exec function.
Captures a full-desktop screenshot and exfiltrates the PNG file to the Discord channel.
Uploads a specified file from the infected machine to the Discord channel.
Table 2: The command prefixes supported by NodeCordRAT.
When NodeCordRAT is run, it will extract the following information from an infected system:
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]".
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’s multilayered cloud security platform detects indicators related to this threat at various levels with the following threat name:
7a05570cda961f876e63be88eb7e12b8
c1c6f4ec5688a557fd7cc5cd1b613649
9a7564542b0c53cb0333c68baf97449c
Obtain Capabilities: Code Signing Certificates
The attacker creates a compelling narrative around a legitimate-looking npm package (via typosquatting) that contains the malicious code.
Compromise Infrastructure: Development Platforms
The attacker uses a typosquatted npm package to distribute the malware, taking advantage of developers downloading or using incorrect package names in their projects.
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.
Obfuscated Files or Information
The original code used minimal obfuscation (hexadecimal characters, uninformative variable names) to confuse automated analysis and frustrate human reverse-engineering.
The script gathers detailed system information, including operating system ( os.platform() ), and executes operating system-specific commands ( wmic , ioreg ) to create a unique fingerprint (UUID/Machine ID) for the compromised host.
System Network Configuration Discovery
The script implicitly relies on network access to establish the Discord connection and C2 channel.
Command and Control (C2)
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.
Unsecured Credentials: Credentials in Files
The script actively searches for and exfiltrates unencrypted or weakly-encrypted files (e.g., .env files) containing sensitive plaintext credentials and configuration secrets.
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.
Data from Local System: File Sharing
The custom !sendfile command allows the threat actor to exfiltrate any specific file from the compromised system's local file system.
The implementation of the !screenshot command allows the attacker to visually monitor user activity and discover sensitive information displayed on the screen.
The script specifically targets the Chrome Login Data and Local State files with the intent to decrypt and harvest protected and saved browser credentials. This also includes the highly targeted exfiltration of LevelDB files found near the MetaMask wallet extension ID.
All sensitive data gathered (e.g., passwords, .env files, screenshots) is uploaded directly to the dedicated Discord C2 channel, using the existing connection for exfiltration.
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.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
