Threat Overview
Checkmarx research highlighted an npm supply-chain campaign centered on the malicious indexed-btree package, which impersonates the legitimate sorted-btree library. Unlike common npm malware, the package avoids install-time lifecycle scripts and hides execution inside normal runtime behavior. Reporting describes a trigger in BTree.prototype.set() and a secondary loader named sharedLoad.min.js. This design can bypass controls focused on preinstall, install, and postinstall scripts.
References
- Checkmarx research reported September 20, 2026; corroborated by current reporting.
- iHeartGeek, September 21, 2026: https://tech.iheartgeek.com/news/npm-indexed-btree-runtime-malware-campaign
Impacted Systems
Node.js/npm developer workstations, CI/CD workers, build systems, and applications that installed affected malicious packages. indexed-btree versions 2.1.1, 2.1.2, and 2.1.3 were reported as malicious. npm replaced the package with a security placeholder. The legitimate sorted-btree package is not the same package.
Why this matters
Runtime-triggered supply-chain malware can expose developer credentials, source-code access, cloud credentials, and CI/CD secrets while evading defenses that focus only on package installation scripts.
Exploitation Status
Confirmed malicious package distribution and runtime execution behavior. Download statistics alone do not prove execution or compromise.
What this hunt looks for
Package artifacts, Node child-process behavior, runtime network connections, new destinations, credential-path access, script creation, and subsequent identity anomalies.
Required logs
Defender XDR DeviceFileEvents, DeviceProcessEvents and DeviceNetworkEvents, plus Microsoft Entra SigninLogs where available.
First Pass – indexed-btree Artifacts
DeviceFileEvents
| where Timestamp >= ago(30d)
| where FileName has_any ("indexed-btree","sharedLoad.min.js")
| project Timestamp,DeviceName,ActionType,FileName,FolderPath,SHA256,InitiatingProcessFileName,InitiatingProcessCommandLine
| order by Timestamp descPackage Manager References
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where FileName in~ ("npm","npm.exe","npx","npx.exe","yarn","yarn.exe","pnpm","pnpm.exe","node","node.exe")
| where ProcessCommandLine has "indexed-btree"
| project Timestamp,DeviceName,AccountName,FileName,ProcessCommandLine,InitiatingProcessFileName
| order by Timestamp descNode Spawning Shells or Child Node
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| where FileName in~ ("node","node.exe","cmd.exe","powershell.exe","pwsh.exe","sh","bash","python","python3")
| project Timestamp,DeviceName,AccountName,InitiatingProcessCommandLine,FileName,ProcessCommandLine,SHA256
| order by Timestamp descRuntime Node Network Activity
DeviceNetworkEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| project Timestamp,DeviceName,InitiatingProcessAccountName,InitiatingProcessCommandLine,RemoteUrl,RemoteIP,RemotePort
| order by Timestamp descNew Node Network Destinations
let Known=DeviceNetworkEvents
| where Timestamp between (ago(30d)..ago(2d))
| where InitiatingProcessFileName in~ ("node","node.exe")
| summarize by DeviceId,RemoteUrl,RemoteIP;
DeviceNetworkEvents
| where Timestamp >= ago(2d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| join kind=leftanti Known on DeviceId,RemoteUrl,RemoteIP
| project Timestamp,DeviceName,InitiatingProcessCommandLine,RemoteUrl,RemoteIP,RemotePort
| order by Timestamp descNode Access to Credential Paths
DeviceFileEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| where FolderPath has_any (".ssh",".aws",".azure",".npm","AppData\\Roaming","Library/Application Support")
| project Timestamp,DeviceName,ActionType,FileName,FolderPath,InitiatingProcessCommandLine
| order by Timestamp descNode-Created Scripts
DeviceFileEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| where ActionType =~ "FileCreated"
| where FileName endswith ".js" or FileName endswith ".ps1" or FileName endswith ".sh" or FileName endswith ".py"
| project Timestamp,DeviceName,FileName,FolderPath,SHA256,InitiatingProcessCommandLine
| order by Timestamp descIdentity Follow-Up – New Sign-In IPs
let Known=SigninLogs
| where TimeGenerated between (ago(30d)..ago(2d))
| summarize by UserPrincipalName,IPAddress;
SigninLogs
| where TimeGenerated >= ago(2d)
| join kind=leftanti Known on UserPrincipalName,IPAddress
| project TimeGenerated,UserPrincipalName,IPAddress,AppDisplayName,ClientAppUsed,ResultType,LocationDetails
| order by TimeGenerated descDetection Notes
The package name and sharedLoad.min.js are higher-signal pivots. Node network and child-process activity is common in developer environments and requires context. Endpoint telemetry is required to observe runtime behavior.