In 2016, a developer named Azer Koculu published a package called "left-pad" to npm - a package that did exactly one thing: pad strings on the left with spaces or zeros. When a trademark dispute with a messaging company caused him to un-publish all his npm packages, the left-pad module disappeared. Within hours, thousands of projects that depended on left-pad - through their own transitive dependency chains - failed to build. React was affected. Babel was affected. The internet noticed that the entire Node.js ecosystem might depend on 11 lines of code published by a single person.
The left-pad incident was a wake-up call about dependency risk. It was also benign - Koculu had no malicious intent. What followed over the next decade was the systematic exploitation of exactly this dependency structure by attackers who understood that injecting malicious code into a widely-used package was more effective than attacking targets directly.
Typosquatting: The Simple Version
The simplest supply chain attack on package managers is typosquatting: register a package name that closely resembles a popular package but contains malicious code. Developers who make a typographical error when installing packages, or who see a similarly-named package recommended somewhere, download the malicious version.
Typosquatting campaigns have been documented on npm (Node.js), PyPI (Python), RubyGems, and other repositories. Common patterns include replacing hyphens with underscores (requests vs requests_), swapping adjacent letters (beutifulsoup4 vs beautifulsoup4), and adding or removing common prefixes or suffixes. Security researchers regularly find hundreds of typosquatting packages on major repositories. Most are caught quickly; some persist for months and are downloaded thousands or millions of times before detection.
Account Takeover: The Sophisticated Version
Rather than creating new malicious packages, attackers increasingly targeted the accounts of legitimate package maintainers. If you can access a maintainer's npm account, you can publish a new version of their package containing malicious code that will be automatically installed by anyone running package updates.
The event-stream attack in 2018 demonstrated this. A popular npm package called event-stream had an aging maintainer (Dominic Tarr) who had largely stopped working on it. A new contributor (using the identity "right9ctrl") contributed legitimate improvements, then requested and received maintainer access. Two months later, they published a new version that included a malicious dependency (flatmap-stream) targeting Bitcoin wallet software - specifically Copay, a product that held cryptocurrency. The malicious code attempted to steal private keys when transaction amounts exceeded a threshold. The attack affected millions of npm downloads before discovery.
The SolarWinds attack was the highest-profile version of this category: not a package manager attack, but the same principle applied to enterprise software update infrastructure. An attacker who can inject code into the build and update process of software installed on thousands of targets has leverage that dwarfs any direct attack.
The PyPI Malware Ecosystem
PyPI has become a particularly active attack surface. Researchers at security firms including ReversingLabs, Sonatype, and Phylum regularly identify campaigns of dozens to hundreds of malicious packages published in coordinated waves. The packages typically contain information stealers - code that collects Discord tokens, browser-stored credentials, cryptocurrency wallet files, and environment variables (which often contain API keys and secrets).
A significant subset of PyPI attacks target developers specifically rather than end users. A developer's machine with repository access, CI/CD credentials, AWS keys, and database connection strings is far more valuable than a typical user's machine. Malicious packages designed to look like developer utilities - debugging tools, code formatters, test utilities - target the people whose machines have the most access.
The Claude AI-related campaign of 2024 was representative: packages named "claude-api", "anthropic-unofficial", and similar names that appeared to be unofficial clients for AI APIs were published to PyPI and downloaded thousands of times before removal. They contained token harvesters and reverse shells targeting developers building on AI platforms.
The Scale Problem
npm hosts over 2 million packages. PyPI hosts over 500,000. The average Node.js project has hundreds of dependencies; the average React application may have a transitive dependency tree of 1,000+ packages. No security team reviews every package in their dependency tree. Automated scanning tools (Dependabot, Snyk, Socket.dev) catch known malicious packages and known-vulnerable versions, but novel attacks by definition are not in any known-bad list when first deployed.
The fundamental tension is between the productivity benefits of the open source ecosystem - software that would take years to build in-house can be assembled in hours from packages - and the security implications of trusting thousands of packages maintained by individual developers whose identity has never been verified, whose machines may be compromised, and whose accounts are protected only by whatever authentication they have chosen to use.
npm's requirement for two-factor authentication on publishing accounts for top packages, PyPI's equivalent Trusted Publishing feature that uses OIDC tokens from CI/CD systems rather than passwords, and package signing standards have incrementally improved the baseline. But the xz-utils case demonstrated that even a well-regarded package with years of history and a trusted maintainer could be compromised through patient social engineering - and that the compromise might not be detected for two years.