Cremit
/incidentsfield log
CatchesCampaignsExfilPatternsLLMIncidentsMethodology
↺rss↗cremit.io

incidents.cremit.io

A reference feed of real-world Non-Human Identity (NHI) credential leak incidents. Maintained by Cremit.

Browse

  • All incidents
  • npm supply chain
  • CI/CD compromise
  • Methodology

Subscribe

  • RSS feed
  • @cremit_io
  • GitHub
// status
monitor active
// build
2026-05-20
// origin
cremit · seoul, kr
// license
CC BY 4.0

© 2026 Cremit. content reuse encouraged with attribution.

home/incidents/event-stream-flatmap-stream-2018
HIGH7.4·confirmed·disclosed Nov 26, 2018·4 min read

event-stream / flatmap-stream Backdoor (2018)

A new maintainer of the popular event-stream npm package added a malicious sub-dependency, flatmap-stream, that exfiltrated cryptocurrency wallet seeds from Copay-derived applications.

Summary

In November 2018, the npm community discovered that event-stream — a widely-depended-on stream utility maintained by Dominic Tarr — had been silently shipping a malicious sub-dependency since September. The original maintainer had handed control of the package to a stranger who claimed they wanted to help maintain it. The new maintainer added flatmap-stream as a dependency, then injected a payload targeting a single downstream consumer: the Copay cryptocurrency wallet. The payload exfiltrated wallet seed phrases and private keys from Copay-derived apps to attacker infrastructure.

Timeline

  • 2018-09-09 — A user named "right9ctrl" gains publish rights to event-stream after asking the original maintainer Dominic Tarr to take over maintenance.
  • 2018-09-09 — event-stream@3.3.6 ships with a new dependency on flatmap-stream@0.1.1, published the same day.
  • 2018-10-05 — flatmap-stream@0.1.2 is published with the malicious payload, encrypted and gated to activate only inside Copay-derived applications.
  • 2018-11-20 — A user notices an unexpected dependency in their tree and opens the GitHub issue that triggers public investigation.
  • 2018-11-26 — npm removes the malicious package; Dominic Tarr publishes his statement; widespread coverage begins.

Attack Vector

The mechanism is a textbook social-engineering takeover of an open-source package, layered with three technical decisions that made the payload hard to spot.

  1. Maintainer handoff via email. The new maintainer asked Tarr for publish rights via cold email. Tarr granted them — event-stream was an unmaintained library he had not touched in years. There was no formal review or identity verification.
  2. Dependency injection rather than direct modification. Rather than modifying event-stream itself, the attacker added a new dependency. Auditors looking at event-stream's diff would not see any malicious code.
  3. Payload obfuscation and target gating. The malicious code in flatmap-stream was AES-encrypted and only decrypted at runtime if specific environment markers (the package name and description of the calling app) matched the Copay wallet. Outside the target environment the code was inert.

Tokens & Credentials Exposed

The payload was narrowly targeted but, when it activated, exfiltrated everything a cryptocurrency wallet needs to be drained:

  • BIP39 mnemonic seed phrases — the master credential for HD wallets.
  • Private keys for individual addresses.
  • Wallet metadata including balances and transaction history, used by the attacker to prioritize which wallets to drain first.

event-stream had roughly 2 million weekly downloads at the time. The malicious sub-dependency was technically present in every install. Only Copay-derived apps activated the payload.

Confirmed Impact

  • Copay wallet versions 5.0.2 through 5.1.0 shipped with the malicious dependency embedded in their bundle.
  • Wallet credential exfiltration is documented; specific dollar-value loss totals were never publicly confirmed by Bitpay (Copay's parent) due to the difficulty of attributing on-chain theft to this specific vector.
  • Trust damage to npm and the maintainer-handoff norm in open-source: this incident is the canonical reference cited every time the topic of unpaid-maintainer burnout meets supply chain risk.

Mitigation & Lessons

The structural lessons are still load-bearing eight years later:

  • Maintainer handoffs are credential transfers. Granting publish rights on a widely-depended package is structurally identical to granting an attacker pre-approved access. There is no built-in identity verification.
  • Sub-dependencies expand your trust boundary silently. A diff against event-stream itself looked clean. The actual malice lived in a new package the diff merely referenced.
  • Lockfile pinning would have helped, but only for organizations that ran npm ci rather than npm install. Re-running npm install would re-resolve flatmap-stream to its latest version, which is exactly when the payload landed.
  • Provenance attestations now exist (added to npm in 2023) for builds running in compliant CI. They would not have prevented this attack — the attacker had legitimate publish rights — but they would make the package itself authenticated to a build pipeline rather than a maintainer's personal credentials.

Cremit Analysis

This incident is a foundational ghost-key case. The npm publish token used to ship the malicious version had no face attached to it once Dominic Tarr handed control over. The new maintainer was, for all npm's purposes, the legitimate owner. There was no anomaly signal — no unusual publish location, no out-of-pattern release cadence — because the legitimate state of the package was now whatever the attacker said it was.

It is also a drifted-key case in a slower sense. event-stream was minted as a small utility years before Copay existed; by 2018 it had drifted into the dependency tree of a wallet handling real money, and the trust model that worked when it was a small utility (one maintainer, no review) was now wildly inappropriate for the blast radius it had accumulated.

The NHI Severity Index score of 7.4 reflects ecosystem-wide reach (every install pulled the dependency) tempered by narrow target activation (only Copay-derived apps activated the payload). Production reachability is unambiguous: the credentials exfiltrated were master keys to live cryptocurrency wallets. Privilege level varied by the user's wallet balance.

The generalizable point — and the one connecting event-stream to ua-parser-js, the Shai-Hulud campaign, and every npm credential incident in between — is that the npm ecosystem treats publish access as a long-lived, transferable credential, and the people who hold those credentials are not always the same people month over month. Identity continuity is something the platform does not enforce; it is something each project has to enforce for itself.


References

  1. [1]
    GitHub Issue dominictarr/event-stream#116 — original disclosure
    primary·2018-11-26·github.com
  2. [2]
    Dominic Tarr — statement on event-stream
    primary·2018-11-26·gist.github.com
  3. [3]
    Compromised npm package: event-stream
    primary·2018-11-27·blog.npmjs.org
  4. [4]
    Widely-used JavaScript library steals BTC from Copay app
    reporting·2018-11-26·zdnet.com

Related incidents

2018-07-12·HIGH
eslint-scope npm Publish Token Theft (2018)
2021-10-22·CRITICAL
ua-parser-js npm Account Compromise (2021)
2026-04-22·CRITICAL
Bitwarden CLI Supply Chain Compromise (2026)
last reviewed / 2026-05-04reviewer / benlicense / CC BY 4.0
// incident metadata
severity
HIGH7.4
status
confirmed
disclosed
2018-11-26
occurred
2018-09-09 → 2018-11-26
vector
npm supply chain
platforms
npm
tokens
API Key (generic)Database CredentialSigning Key
nhi severity index
score7.4 / 10blast radiusecosystem-widereachabilityproductionprivilegevariable
nhi kill chain
Ghost Key↗Drifted Key↗
metrics
exposure78 days