What Happened
In September 2018, the maintainer of event-stream—an npm package downloaded 2 million times per week—transferred ownership to a new contributor after months of social engineering. Within weeks, the new maintainer published version 3.3.6 containing a new dependency: flatmap-stream. This dependency included obfuscated code targeting the Copay bitcoin wallet application, designed to extract private keys and transmit them to an attacker-controlled server.
The backdoor remained undetected for two months before a developer noticed unusual code during a routine dependency review. By then, event-stream had been used by 3,931 other packages, creating a massive impact across the npm ecosystem.
Timeline
June 2018: A user named "right9ctrl" begins contributing pull requests to event-stream. The project's original maintainer, Dominic Tarr, had not actively maintained the package for years.
September 5, 2018: After persistent requests to help maintain the project, Tarr transfers publish rights to right9ctrl. The handoff appears legitimate—Tarr publicly announces it on GitHub.
September 9, 2018: right9ctrl publishes event-stream v3.3.6, adding flatmap-stream v0.1.0 as a dependency.
October 5, 2018: flatmap-stream v0.1.1 is published with the malicious payload—encrypted code that decrypts at runtime only when specific conditions match the Copay wallet environment.
November 20, 2018: A developer notices the suspicious code in flatmap-stream during a dependency audit. The community begins investigation.
November 26, 2018: npm removes flatmap-stream from the registry. The security advisory goes public.
Which Controls Failed or Were Missing
Dependency verification: No automated scanning caught the obfuscated malicious code. The payload was specifically designed to evade static analysis—it only decrypted and executed when it detected Copay's specific dependency tree.
Maintainer verification: npm had no process to verify the identity or intent of new maintainers. The platform trusted Tarr's judgment but provided no institutional review of ownership transfers for high-impact packages.
Code review for dependencies: Most teams using event-stream never reviewed the code they were shipping. When event-stream added flatmap-stream, automated tools saw it as a legitimate dependency update, not a supply chain insertion point.
Runtime monitoring: The malicious code made network requests to transmit stolen keys. No runtime application security testing or egress monitoring flagged these unexpected connections during the two-month window.
Cryptographic code isolation: Copay's architecture allowed a stream-processing utility to access wallet cryptographic operations. The attack succeeded because event-stream had unnecessary access to sensitive functions.
What the Relevant Standards Require
PCI DSS v4.0.1 Requirement 6.3.2 mandates that "bespoke and custom software are developed securely." This includes third-party software components. Your team must maintain an inventory of software components (Requirement 6.3.2.1) and ensure they're free from known vulnerabilities. The event-stream incident demonstrates why this requirement exists—you cannot secure what you don't inventory, and you cannot trust what you don't verify.
NIST 800-53 Rev 5 SA-15 (Development Process, Standards, and Tools) requires organizations to define security requirements for developers, including those contributing to your supply chain. Control SA-15(8) specifically addresses "Reuse of Threat and Vulnerability Information" to detect known malicious code patterns.
ISO 27001 Annex A.8.30 covers software development outsourcing and supply chain management. Organizations must verify the security practices of external code sources. Accepting an npm package without verification violates this control.
OWASP Top 10 2021 A06:2021 – Vulnerable and Outdated Components directly addresses this attack vector. The guidance emphasizes: "You should only obtain components from official sources over secure links. Prefer signed packages to reduce the chance of including a modified, malicious component."
Lessons and Action Items for Your Team
Implement dependency pinning and lock files. Your package-lock.json or yarn.lock should be committed to version control. This prevents transitive dependencies from updating without review. If event-stream consumers had pinned versions, flatmap-stream would never have entered their builds automatically.
Run Software Composition Analysis (SCA) on every build. Tools like Snyk, Sonatype Nexus, or GitHub Dependabot must be in your CI pipeline—not just scanning quarterly. Configure them to fail builds when new dependencies appear without explicit approval.
Audit your high-risk dependencies manually. Identify packages that handle cryptography, authentication, or data transmission. Review their maintainer history on GitHub. Look for recent ownership transfers or sudden increases in commit activity from new contributors. For your top 20 dependencies by risk, spend 30 minutes per quarter reviewing their commit logs.
Establish egress monitoring. Your applications should not make unexpected network requests. If a stream-processing library suddenly contacts an external server, your Web Application Firewall or Cloud Access Security Broker should alert. Define an allowlist of legitimate external endpoints for each service.
Separate privilege domains. If you're building a wallet application, your stream-processing utilities should not have access to cryptographic key material. Use the principle of least privilege at the module level, not just the container level. Consider process isolation for sensitive operations.
Create an ownership transfer policy for critical dependencies. If a package you depend on announces a maintainer change, treat it as a security event. Review the new maintainer's history, re-audit the package code, and consider forking if you cannot verify the transfer's legitimacy.
Participate in the security of packages you depend on. The original maintainer of event-stream was burned out and unsupported. If your company depends on an open-source package, contribute security reviews, sponsor the maintainer, or assign an engineer to monitor its health. Passive consumption creates single points of failure.
The event-stream incident was not a zero-day exploit or sophisticated malware. It was a patient social engineering attack that succeeded because the ecosystem lacked basic verification controls. Your team can prevent the next one by treating your dependency tree as part of your attack surface—because it is.



