NPM-EVENT-STREAM-2018
Summary
The event-stream incident, disclosed in November 2018, was the wake-up call for npm supply-chain security, and a preview of the xz backdoor six years early. event-stream was a popular but unglamorous Node.js utility with around two million weekly downloads and a maintainer who had lost interest. When a stranger offered to take it over, the maintainer simply handed it off, no vetting, as open-source volunteers exhausted by unpaid work often do. The new "maintainer" then, patiently, slipped in a malicious dependency that was surgically targeted: it did nothing on almost every machine, activating only inside the build of a specific Bitcoin wallet app, where it tried to steal the private keys of anyone holding a large balance. It is the original lesson that a dependency is a person you are trusting, and that a maintainer handoff is a supply-chain attack surface.
How it happened
event-stream's original author, Dominic Tarr, had long since moved on; the package still had around two million weekly downloads but no active steward. A GitHub user going by "right9ctrl" emailed offering to maintain it, and Tarr, like many burnt-out maintainers, granted publish rights to a willing volunteer. ("He emailed me and said he wanted to maintain the module, so I gave it to him," Tarr later wrote. "I don't get anything from maintaining this module, and I don't even use it anymore.") It was a well-meaning, ordinary act, and it handed control of a hugely popular package to an attacker.
The takeover was patient, foreshadowing xz. In version 3.3.6 (published 9 September 2018) the new maintainer added a new dependency, flatmap-stream, that was still completely benign, building trust. Almost a month later, on 5 October, they published a poisoned flatmap-stream@0.1.1 carrying the payload, without touching event-stream itself, so the popular package became dangerous retroactively. The concealment was the clever part: the malicious code existed only in the minified package published to npm, not in the GitHub source, so anyone reviewing the repository saw nothing. It was also encrypted, using the description of its intended victim package ("A Secure Bitcoin Wallet") as the decryption key, so it stayed inert everywhere except where it was meant to fire. That target was Copay, a Bitcoin wallet built by BitPay. Inside a Copay release build, the backdoor decrypted, modified the bundled wallet code, and harvested wallet private keys and recovery seeds for accounts holding more than 100 BTC or 1000 BCH, sending them to an attacker's server. Copay versions 5.0.2 through 5.1.0 shipped it.
The damage
Because the targeting was so narrow, the confirmed direct theft was limited, and Copay patched quickly once it was found. The damage was conceptual, and enormous. event-stream proved that a trusted, ubiquitous dependency could be weaponised for nothing more than a friendly offer to help, that the payload could be hidden from anyone reading the source, and that it could be aimed with a sniper's precision at a single downstream application. npm removed the malicious packages and took ownership of event-stream itself to stop further abuse, and the episode pushed npm and the ecosystem toward two-factor authentication, audit tooling, and a general loss of innocence about npm install.
Why event-stream still matters
event-stream is the prototype for the entire modern supply-chain playbook. Social-engineering a maintainer handoff (later perfected in the xz backdoor). Adding a dependency while it is still clean and weaponising it weeks later, so the trust is earned before the betrayal. Hiding the malware in the published artifact rather than the source, so review misses it. Surgically targeting one downstream victim. Every one of those techniques is now standard. The lessons it teaches are still the right ones: a dependency is a trust relationship with whoever controls it, so treat ownership changes as security events; pin and review dependency updates, especially new transitive packages that appear quietly; build from reviewed source and compare against what is actually published; and keep your dependency tree small, because every package is one more overworked, unpaid maintainer you are implicitly trusting.
How to fix it
- Remove the malicious version (specifically `flatmap-stream@0.1.1`, and event-stream 3.3.6 which pulls it in), pin to a known-good release, and rebuild and republish anything that bundled it.
- For affected apps like the Copay wallet, treat exposed private keys and funds as compromised and move funds to new wallets generated on a clean system.
- Audit what the dependency could reach, and rotate any secrets handled by code that ran alongside it.
How to avoid it
- Treat a maintainer or ownership change on a dependency as a security event worth reviewing, not a routine update.
- Pin dependencies and review updates, especially a new transitive dependency a package suddenly pulls in; flatmap-stream arrived exactly that quietly, then turned malicious weeks later.
- Build from reviewed source where you can and compare it against the published artifact; the payload lived only in the npm tarball, not the GitHub repo.
- Reduce dependency sprawl: every package you add is a maintainer you are trusting, often an unpaid and overworked one, so keep the tree small and watch the ones that touch anything sensitive.
References
Related vulnerabilities
All Supply chain →- CRITICALGHSA-93qj-5q5v-3c2h
Trojanized pantheon-agents 0.6.1 and 0.6.2 on PyPI ship a credential stealer (supply-chain account compromise)
- CRITICALNPM-REDHAT-MIASMA-2026
In June 2026 the npm supply-chain worm finally produced something genuinely new and frightening: malicious packages that were signed and carried valid build provenance. Attackers used a compromised GitHub account inside Red Hat's own organisation to publish trojanised versions of 31 packages in the @redhat-cloud-services namespace through Red Hat's legitimate CI pipeline, so the poisoned releases arrived with authentic attestations proving they were built by the real build system. The payload, nicknamed Miasma, was a lightly re-skinned copy of Mini Shai-Hulud, a worm that a group called TeamPCP had open-sourced for anyone to reuse weeks earlier. No Red Hat customers were harmed, because Red Hat strips install scripts before deployment, but the permanent lesson is uncomfortable: a signature proves where a package was built, not that the build was clean.
- CRITICALNPM-AXIOS-2026
On 31 March 2026 the single most widely used HTTP client in the JavaScript world was turned into malware for about three hours. Axios carries well over 100 million weekly downloads and sits as a transitive dependency underneath a huge share of the npm ecosystem, so when a North Korea-nexus actor took over the maintainer's account and published two booby-trapped versions, the blast radius was enormous even though the bad versions were live only for one early-morning window. The poisoned releases pulled in a hidden dependency that ran on install and dropped a cross-platform remote access trojan onto developer machines and CI runners. It is the case study in why a few hours of a popular package being compromised is still a global incident, and in why a maintainer's own laptop is now a nation-state target.
- HIGHSC-NOTEPADPP-CHRYSALIS-2025
In 2025, a Chinese state-linked espionage group hijacked the update channel of Notepad++, one of the most widely installed Windows text editors, to plant a custom backdoor on a handful of carefully chosen targets. The attackers never touched Notepad++'s source code or its signing keys. Instead they compromised the third-party shared-hosting server that delivered updates, and abused the fact that the WinGUp updater shipped without any integrity check on what it downloaded (tracked as CVE-2025-15556). For machines on their target list, WinGUp was silently redirected to attacker-controlled servers that served a trojanized installer; everyone else kept receiving the genuine update. The campaign ran from roughly June to December 2025 and was only made public in February 2026 by Rapid7, with Kaspersky and Broadcom/Symantec corroborating it independently.
- HIGHSC-ESCAN-RELOAD-2026
On or around January 20, 2026, attackers who had broken into a regional update server for eScan, the antivirus product made by India's MicroWorld Technologies, pushed a trojanized Reload.exe through the legitimate update channel during a window of roughly two hours. The security software itself became the delivery vehicle for malware. The malicious binary carried eScan's code-signing identity, but its signature was actually invalid; it ran anyway because the updater trusted the channel rather than rigorously validating the signature. Once on a host, the malware rewrote the Windows HOSTS file to cut eScan off from its own update servers, blinded script scanning, and reached out to takedown-resistant command-and-control hosted on blockchain naming systems. Morphisec disclosed the campaign, with Kaspersky and Darktrace corroborating it independently.
- CRITICALNPM-SHAI-HULUD-2-2025
Shai-Hulud is the nightmare the npm ecosystem had long feared: a self-replicating worm. First seen in September 2025 and back in a more aggressive wave around 21-24 November 2025 ("The Second Coming"), it does not just poison one package and wait. When its malware runs in a developer's environment, it harvests every secret it can find, npm tokens, GitHub tokens, cloud keys, then uses those stolen npm tokens to automatically publish itself into other packages the victim maintains, spreading from maintainer to maintainer on its own. The second wave hit more than 25,000 GitHub repositories across roughly 500 compromised accounts, leaked the stolen secrets into public repos, and, if it failed to steal credentials, tried to wipe the victim's home directory. It is the moment supply-chain malware learned to propagate like a biological infection.