Fake Roblox packages target npm with Luna Grabber info-stealing malware

ReversingLabs discovered a supply-chain campaign on npm where typosquatted packages impersonating the noblox.js Roblox API delivered a multistage payload that installed Luna Grabber. The attack used a malicious postinstall.js to fetch a second-stage script from Discord CDN which then retrieved a PyInstaller executable; #LunaGrabber #nobloxjs #ReversingLabs #Roblox

Keypoints

  • Malicious npm packages (noblox.js-vps, noblox.js-ssh, noblox.js-secure) typosquatted on the legitimate noblox.js package to target Roblox developers.
  • Attackers embedded malicious logic in a postinstall.js that runs after package installation to perform OS checks and trigger payload delivery.
  • The postinstall stage contacted the Discord CDN to download a second-stage script, which then fetched a PyInstaller-compiled Luna Grabber executable.
  • Authors iteratively updated and partially obfuscated postinstall.js across versions, evolving from username harvesting to full multistage deployment.
  • Luna Grabber (the final payload) is open-source and configurable via a builder; it collects browser/Discord/local system data and includes sandbox/VM detection and self-destruct features.
  • ReversingLabs enumerated package versions and SHA1 hashes for the malicious npm packages, second-stage scripts, and the final executable as IOCs.
  • The campaign had limited impact (under ~1,000 combined downloads) and affected only a small number of users before removal.

MITRE Techniques

  • [T1195] Supply Chain Compromise – Malicious npm packages impersonated a legitimate library to deliver malware (‘malicious npm packages that also typo-squatted on the noblox.js package’).
  • [T1059] Command and Scripting Interpreter – Post-install JavaScript executed commands and scripts on the host during installation (‘executing commands in the command line’).
  • [T1105] Ingress Tool Transfer – The postinstall script downloaded a second-stage payload and a third-stage executable from online hosts (Discord CDN) (‘it downloads a second-stage malicious script from Discord CDN and runs it’).
  • [T1027] Obfuscated Files or Information – Later versions of postinstall.js contained obfuscation to hide malicious behavior (‘subsequent versions obfuscated parts of the postinstall.js script’).
  • [T1082] System Information Discovery – The malicious code harvested local user and system information such as Windows usernames (‘harvesting the Windows username to the provided Discord webhook’).
  • [T1497] Virtualization/Sandbox Evasion – The Luna Grabber payload included checks to detect virtual environments and a self-destruct mechanism (‘ability to detect if it is being run in a virtual environment as well as a self-destruct feature’).

Indicators of Compromise

  • [npm package] Malicious package names observed – noblox.js-vps, noblox.js-ssh (typosquatting noblox.js).
  • [Package SHA1] Example malicious package hashes – noblox.js-vps 4.23.0: 21d368c68b40fc0a9f5403cc1d9160cd2326d8ee, noblox.js-vps 4.14.0: 6c5c33d7dc70e18287dff364dea6f75395f13d5e (and many other version hashes).
  • [Second-stage SHA1] Second-stage payload hashes – 968963b2950e4f8571a9ca84db69d6482335cfc1, 21fa7478e0b7d5fc1752cdff9659095229fc0b1c (and 3 more hashes).
  • [Executable SHA1] Malicious PyInstaller executable – a94e7c7b429d2da3e319ad1384e48240539ac169 (final-stage Luna Grabber sample).
  • [File name] Malicious script file used in packages – postinstall.js (used to trigger second-stage download and execution).

Rewriting focusing on technical procedure:
Attackers created npm packages that closely replicated the legitimate noblox.js codebase but inserted a malicious postinstall.js script to run automatically after installation. Early versions of the package contained non-malicious or development-stage postinstall logic; subsequent releases added Windows-specific checks and began exfiltrating the local Windows username to an attacker-controlled Discord webhook, then evolved to fetch and execute a remote second-stage script hosted on Discord’s CDN. Over multiple iterations the postinstall script was partially obfuscated to hinder analysis.

The second-stage script consistently attempted to download a third-stage payload: a PyInstaller-compiled executable identified as Luna Grabber. ReversingLabs extracted luna.py from inside the executable and matched it to Luna Grabber’s public GitHub implementation. Luna Grabber is modular and builder-driven, allowing operators to toggle features (browser/Discord data collection, startup persistence, injection, ping callbacks); the samples in this campaign were configured primarily to collect system information and included VM/sandbox detection and a self-destruct capability.

Detection came from repository monitoring and static/behavioral analysis: indicators observed included specific package names, versioned SHA1 hashes for packages and second-stage scripts, the postinstall.js file pattern that checks OS and downloads remote code, and the final executable hash (a94e7c7b429d2da3e319ad1384e48240539ac169). The campaign’s multistage flow—typosquat → postinstall execution → Discord CDN fetch → PyInstaller Luna Grabber execution—illustrates how open-source components can be abused to deliver configurable, turnkey stealers via supply-chain vectors.

Read more: https://www.reversinglabs.com/blog/fake-roblox-api-packages-luna-grabber-npm