- Table of contents
The Great NPM Heist – September 2025
On September 8, 2025, the JavaScript ecosystem experienced what is now considered the largest supply chain attack in npm history. A sophisticated phishing campaign led to the compromise of a trusted maintainer’s account, resulting in the injection of cryptocurrency-stealing malware into 18+ foundational npm packages. These packages collectively accounted for over 2 billion weekly downloads, affecting millions of applications globally—from personal projects to enterprise-grade systems.
Following the discovery of the breach, the npm team began removing several of the malicious package versions published by the attackers, including the compromised debug package, which alone sees over 357 million downloads each week.
Initial Compromise: A Phishing Attack with Devastating Reach
The attack began when Josh Junon, a prolific open-source maintainer known as Qix-, received a phishing email impersonating npm support. The email, sent from support@npmjs.help (a domain registered just three days earlier), warned that his account would be locked unless he updated his 2FA credentials within 48 hours.
Under pressure and during what he described as a “panicky morning,” Junon clicked the link and entered his credentials. This gave the attackers full access to his npm account. Within minutes, they began publishing malicious versions of his packages.
Infrastructure
The threat actor opened a new domain – “npmjs.help” on September 5th, 3 days before the event occurred. At the time of writing, this domain is no longer accessible, but records show that it once resolved to 185.7.81.108.
This email contained a link to https://www.npmjs[.]help/settings/qix/tfa/manageTfa?action=setup-totp, which loaded content from two attacker-controlled BunnyCDN buckets: static-mw-host.b-cdn[.]net and img-data-backup.b-cdn[.]net.
One of the scripts loaded was the credential stealer, which can be found here. This is a simple script which stores the provided username, password, and 2FA code, and sends it to a remote host at websocket-api2.publicvm[.]com.
Reports from recipients of the phishing message indicate that the campaign also targeted other package maintainers and developers who shared the same email domain or address format.
Affected Packages
The compromised packages included some of the most widely used utilities in the JavaScript ecosystem:
- backslash (0.26m downloads per week)
- chalk-template (3.9m downloads per week)
- supports-hyperlinks (19.2m downloads per week)
- has-ansi (12.1m downloads per week)
- simple-swizzle (26.26m downloads per week)
- color-string (27.48m downloads per week)
- error-ex (47.17m downloads per week)
- color-name (191.71m downloads per week)
- is-arrayish (73.8m downloads per week)
- slice-ansi (59.8m downloads per week)
- color-convert (193.5m downloads per week)
- wrap-ansi (197.99m downloads per week)
- ansi-regex (243.64m downloads per week)
- supports-color (287.1m downloads per week)
- strip-ansi (261.17m downloads per week)
- chalk (299.99m downloads per week)
- debug (357.6m downloads per week)
- ansi-styles (371.41m downloads per week)
These packages are deeply embedded in thousands of other npm modules, creating a massive blast radius.
Malware Behaviour: A Sophisticated Crypto Heist
The injected malware was browser-specific and designed to steal cryptocurrency in two primary ways:
- Passive Address Replacement
- The malware hooked browser functions like fetch, XMLHttpRequest, and window.ethereum.
- It scanned for cryptocurrency wallet addresses in network traffic.
- When detected, it replaced them with attacker-controlled addresses using visually similar strings to avoid detection.
- Active Transaction Hijacking
- For users with browser wallets (e.g., MetaMask, Phantom), the malware intercepted transaction requests before signing.
- It modified the destination address in real time, while still displaying the original address to the user.
A deep dive into the obfuscated malware injected into several popular NPM packages reveals a highly sophisticated browser-based attack targeting cryptocurrency transactions. The malicious code was engineered to intercept outgoing wallet transactions and covertly replace the destination address with one controlled by the attacker. This substitution is made deceptively subtle by using the Levenshtein distance algorithm to select attacker-controlled addresses that closely resemble the original, making manual detection difficult.
According to Charlie Eriksen from Aikido Security, the malware functions as a multi-layered interceptor. It hijacks both network traffic and application APIs, including window.fetch, XMLHttpRequest, and window.ethereum.request, as well as other wallet provider interfaces. This enables it to manipulate both the data being sent and the responses received, effectively rewriting transaction details in real time.
The payload begins by verifying it’s running in a browser environment (typeof window !== ‘undefined’) and then hooks into critical APIs. If a user visits a site that includes the compromised code and has a connected wallet (e.g., MetaMask or Phantom), the malware can intercept and alter transactions before they are signed. While developers aren’t the primary targets, they can still be affected if they connect wallets while testing or browsing affected sites.
Targeted Cryptocurrencies:
- Bitcoin (Legacy & SegWit)
- Ethereum
- Tron
- Litecoin
- Bitcoin Cash
Timeline of Events
- Sept 5: Attackers register npmjs.help domain.
- Sept 8, 13:00 UTC: Phishing email sent to Junon.
- 13:16 UTC: First malicious package published.
- 13:21 UTC: Aikido Security detects anomaly.
- 14:16 UTC: Public disclosure begins.
- Evening: npm starts removing malicious versions.
- Sept 9: Some packages (e.g., simple-swizzle) still compromised.
Detection & Response
Aikido Security detected the attack within 5 minutes of the first malicious package being published. Their systems flagged unusual behavior in build pipelines, including ReferenceError: fetch is not defined—a result of the malware trying to run in Node.js environments.
Recommendations
For Developers & Teams:
- Use npm ci instead of npm install to enforce lockfile integrity.
- Pin package versions using overrides in package.json.
- Audit dependencies regularly with tools like npm audit, Snyk, or Socket.dev.
- Review lockfile changes in pull requests.
- Enable 2FA with hardware keys for all maintainer accounts.
For End Users:
- Verify all crypto transactions before signing.
- Use hardware wallets for large holdings.
- Monitor wallet activity for anomalies.
- Update applications using affected packages.
IOCs
URLs
http://npmjs.help/
https://uixie.npmjs.help/
https://npmjs.help/
http://support@npmjs.help/
https://www.npmjs.help/
Domain
npmjs.help
IP
185.7.81.108
support@npmjs.help
About Cyberint, Now a Check Point Company
Cyberint, otherwise known as Check Point External Risk Management, reduces risk by helping organizations detect and mitigate external cyber threats before they have an adverse impact.
The solution provides superior visibility through continuous discovery of the evolving attack surface, combined with the automated collection and analysis of vast quantities of intelligence from across the open, deep and dark web.