Malicious npm Package With Millions of Downloads Hid Its Payload Until Runtime
A package published to npm as indexed-btree spent months looking like an ordinary sorting utility. It copied the identity and reputation of a legitimate library called sorted-btree, and in doing so pulled in close to two million weekly downloads — evidence of how deep it had worked its way into other projects' dependency trees before anyone noticed.
What happened
Researchers at Checkmarx found that indexed-btree carries no preinstall or postinstall script, the kind of red flag that automated scanners and quick manual reviews are trained to catch. That absence made the package look clean. The actual payload sits inside BTree.prototype.set, a core method almost any application using the library will eventually call. Only when that method fires does the malicious routine wake up — long after installation, and well past the point most security checks stop looking.
Once triggered, the first stage collects basic host information — operating system, architecture, hostname, processor, memory and uptime — and reports it to attacker-controlled infrastructure. Instead of reaching out to a conventional command-and-control server, it queries a smart contract deployed on the Ethereum Sepolia test network. That choice makes the operation harder to disrupt: if a destination gets blocked, the operators can simply point the contract at a new one. A cryptographic key exchange then derives a decryption key and assembles a second-stage payload from data returned by the contract. Cleanup routines built into the package can later delete the dropped files and erase the trigger from the prototype method, limiting the evidence left behind.
Checkmarx also traced a wider cluster of related packages — among them ordered-kv-index, btree-leaderboard, btree-core and several others — plus an earlier package, mutex-forge, tied to the same smart contract. The attackers backed the campaign with a convincing GitHub commit history, adding the kind of routine-looking activity that makes a package pass a casual trust check.
Why it matters
The campaign is a clean example of a blind spot in how many teams vet open-source dependencies: treating the absence of install-time scripts as proof a package is safe. That check says nothing about behavior baked into the library's own functions, which only runs once the code is actually imported and used. With roughly two million weekly downloads behind the disguise, any organization pulling data-structure utilities into build pipelines, test environments or production services has reason to check whether this one made it in.
What to do
- Search source trees, lockfiles, build images, developer workstations and CI systems for
indexed-btreeand the related package names listed below. - Remove any matches, rotate secrets that may have been exposed, and review logs against the indicators of compromise.
- Treat "no lifecycle script" as necessary but not sufficient — review what a package's exported functions actually do, not just what runs on install.
- Where possible, run unfamiliar packages in an isolated environment and watch for child processes, filesystem changes and outbound network calls triggered after normal use — not just at install time.
- Pin reviewed dependency versions, maintain a current software bill of materials, and require review for new or unexpectedly changed packages.
Indicators of compromise: malicious packages indexed-btree, ordered-kv-index, btree-leaderboard, priority-slot-queue, btree-range-store, btree-core, btree-time-index, btree-lru-cache, neighbor-key-map, sliding-score-window; related package mutex-forge; dropped file sharedLoad.min.js; an Ethereum Sepolia smart contract used as a C2 channel, plus associated RPC endpoints, Telegram and Slack exfiltration tokens, and a hardcoded X25519 public key. Full technical detail, including the GitHub repository and contract address, is in the source report.
Source: Cyber Security News (Tushar Subhra Dutta)
