The background
A popular NPM maintainer was compromised today which led to 18 NPM packages having malicious packages published to the NPM registry.

The maintainer, Josh Junon, was successfully phished from an email purporting to be from NPM but really came from a lookalike domain "npmjs[.]help":

Once the maintainer was compromised, the threat actors rushed to push out malicious versions of his packages. Josh helps maintain some VERY popular packages and the impact was felt really quickly. The affected packages are downloaded over 2 billion times a week! This is a massive attack!
The affected packages and versions are:
ansi-regex - 6.2.1
ansi-styles - 6.2.2
backslash - 0.2.1
chalk - 5.6.1
chalk-template - 1.1.1
color-convert - 3.1.1
color-name - 2.0.1
color-string - 2.1.1
debug - 4.4.2
error-ex - 1.3.3
has-ansi - 6.0.1
is-arrayish - 0.3.3
simple-swizzle - 0.2.3
slice-ansi - 7.1.1
strip-ansi - 7.1.1
supports-color - 10.2.1
supports-hyperlinks - 4.1.1
wrap-ansi - 9.0.1
What does this malware do?
Core Functionality: Crypto Address Swapping
The payload is in the src/index.js file which is heavily obfuscated. The index.js file appears to be a crypto drainer and is targeting several common cryptocurrencies. The primary malicious action is to replace cryptocurrency wallet addresses found on websites with addresses belonging to the attacker.
newdlocal()
function: This is the main function that initiates the hijacking. It does two things:- Overrides Network Requests: It monkey-patches the
fetch
API andXMLHttpRequest
to intercept all incoming and outgoing HTTP requests. This allows it to inspect and modify the content of web pages. - Address Scanning and Replacement: For every HTTP response, it calls the
_0x19ca67
function, which in turn uses_0x20669a
to scan the text for cryptocurrency addresses.
- Overrides Network Requests: It monkey-patches the
_0x20669a
function: This is the heart of the address replacement logic.- It contains hardcoded arrays of attacker-owned cryptocurrency addresses for:
- Bitcoin (BTC)
- Bitcoin Cash (BCH)
- Ethereum (ETH)
- Litecoin (LTC)
- Tron (TRX)
- Solana (SOL)
- It uses a set of regular expressions (
_0x3ec3bb
) to find potential crypto addresses in the text. - If a found address does not belong to the attacker's list, it replaces it with one that does. To make the replacement less obvious, it uses a Levenshtein distance algorithm (
_0x3479c8
and_0x2abae0
) to pick an address from its list that is visually similar to the original one.
- It contains hardcoded arrays of attacker-owned cryptocurrency addresses for:
This is the regex that tells us what the threat actors were targeting!

MetaMask Transaction Hijacking
The script has a special module, runmask()
, dedicated to attacking users of the MetaMask browser wallet.
checkethereumw()
andrunmask()
: The script first checks for the existence ofwindow.ethereum
, which is the object MetaMask injects into web pages. If found, it executesrunmask()
.- Intercepting
eth_sendTransaction
: Therunmask
function wraps thewindow.ethereum.request
method. This allows it to intercept all calls made to the user's wallet. When it detects a call toeth_sendTransaction
, it modifies the transaction details before they are presented to the user for signing. - Malicious Transaction Modification (
_0x1089ae
function):- Redirecting ETH transfers: For a standard Ether transfer, it replaces the legitimate recipient's address (
to
) with the attacker's hardcoded address. - Stealing Tokens via
approve
: It looks for transaction data corresponding to a tokenapprove
call (identified by the function selector0x095ea7b3
). It then replaces the address that is being granted approval with the attacker's address, effectively giving the attacker the ability to drain all of that user's tokens. - Hijacking DEX Swaps: It identifies interactions with decentralized exchanges like Uniswap, PancakeSwap, and SushiSwap and modifies the transaction data to divert the swapped funds.
- Redirecting ETH transfers: For a standard Ether transfer, it replaces the legitimate recipient's address (
Lookalike NPM domains continue to deliver results for bad guys
The phishing email that started this mess came from the domain npmjs[.]help. This is the second or third time in recent months where simple lookalike domains have been used to successfully phish popular NPM maintainers. When is NPM going to get proactive and buy these domains ahead of time?
The domain was purchased and initially hosted on September 5th. The subdomains all used a single VPS server in the Netherlands:

More victims come to light
Unfortunately, several other NPM maintainers were also targeted in this attack, and have added additional information on a HackerNews post.
So far its unknown how many NPM maintainers got phishing emails, but we will update this blog post as we receive more information!
Let us know if this blog post helped you
Hit me up directly if you have any questions about this campaign.

Paul McCarty - Head of Research, Safety
You can find me on LinkedIn and BlueSky.