This is episode one of What Did I Just Install.
On a Tuesday afternoon in March twenty sixteen, deployment pipelines at Facebook, Netflix, and Spotify failed within minutes of each other. Not one of them had pushed a code change. The errors were identical. A four oh four. A missing package, something called left-pad that none of these companies had ever directly installed but that thousands of their indirect dependencies pointed to. Within ten minutes, the failures were cascading across the JavaScript ecosystem. React would not build. Babel would not compile. If your company used JavaScript in any serious capacity, something in your stack had just quietly broken.
The cause was eleven lines of code. A function that pads the left side of a string with spaces. It had been deleted from the internet by one developer who was sitting in a building at Lucasfilm's campus in San Francisco, and the whole thing had started with a trademark dispute about a messaging app.
This is the story of left-pad. It is also the story of how the JavaScript ecosystem accidentally proved that the modern web was held together with string and good intentions. But to tell it properly, you need to understand the people, because there are more of them than you might expect, and their stories are stranger.
Azer Koculu is a Turkish software engineer. In early twenty sixteen, he was working at Jelly, the search engine startup founded by Twitter co-founder Biz Stone. Jelly's offices were in the Letterman Digital Arts Center in the Presidio, the campus that George Lucas built in San Francisco. It is a peculiar place to be writing small JavaScript utilities, surrounded by the infrastructure of a film empire.
Koculu was a prolific open source contributor with over two hundred and seventy packages on npm. Most were small, single-purpose utilities following the Unix philosophy of doing one thing well. One of them was called kik, a little command-line tool for scaffolding web projects. It had nothing to do with the Canadian messaging company of the same name. Another was called left-pad.
What is harder to find in the public record is who Koculu actually was beyond his npm profile. He spent his weekends camping in remote areas without cell phone service. He was ideological about open source in a way that went beyond writing code, he believed npm was a commons, a shared space where individuals contributed freely and no corporation got to override the people who built things. He would later describe himself as someone guided by personal conviction rather than anger or greed. Whether you believe that framing depends on how you read what happened next.
In early March twenty sixteen, Koculu received an email from a man named Bob Stratton, a patent and trademark agent doing contract work for Kik Interactive, the Canadian company behind the Kik messaging app. Kik had over two hundred million registered users at the time. They were preparing to release their own npm package and wanted the name.
Koculu's response was immediate. Sorry, he wrote, I am building an open source project with that name.
Stratton wrote back, and this is where the tone shifts.
We don't mean to be a dick about it, but it's a registered trademark in most countries around the world and if you actually release an open source project called kik, our trademark lawyers are going to be banging on your door and taking down your accounts and stuff like that, and we'd have no choice but to do all that because you have to enforce trademarks or you lose them. Can we not come to some sort of compromise to get you to change the name without involving lawyers? Is there something we could do for you in compensation to get you to change the name?
Read that again from Koculu's perspective. A corporation with two hundred million users is telling a solo developer that they will unleash their lawyers unless he gives up the name of his personal project. The word "dick" is in the message. The offer of compensation is buried under the threat.
Koculu's response was not diplomatic.
Hahah, you're actually being a dick. So, fuck you. Don't email me back.
He also named a price, thirty thousand dollars, for the hassle of giving up his pet project for, in his words, a bunch of corporate dicks. Whether the thirty thousand was a genuine demand or a deliberately insulting number designed to end the conversation is something sources disagree on. What is clear is that the conversation was over. Stratton went to npm directly.
To understand what happened next, you need to know who was running npm. Isaac Schlueter is not the kind of person you would expect to be holding the keys to the JavaScript ecosystem.
Schlueter dropped out of Southern Connecticut State University around two thousand because he could not afford tuition. This was during the dotcom bust, and the job market was brutal. He could not get hired in tech. He could not even get hired at fast food restaurants. He was competing against people with PhDs for entry-level positions. To survive, he sold vacuum cleaners door to door.
Eventually he made it to California, got a job doing tech support for a medical billing software company, and taught himself VBScript, JavaScript, CSS, and PHP. A recruiter at Yahoo noticed his HTML-formatted resume posted online, and by two thousand six he was on the Yahoo User Interface platform team. That is where he developed a taste for package managers. When Node.js appeared in two thousand nine, Schlueter saw what was missing. Developers were manually copying code between projects. He started building a tool to automate it. npm, the Node Package Manager, had its first usable version by early twenty ten.
In twenty fourteen, Schlueter founded npm, Inc., with Laurie Voss and Rod Boothby. They raised two point six million dollars in seed funding from True Ventures, followed by a Series A that brought the total to roughly ten million dollars. The idea was that npm needed commercial revenue to sustain the explosive growth of the registry. Schlueter rejected a foundation model because, as he put it, costs that are growing exponentially cannot work with donation-based funding. He believed a company was the only structure that could keep the free registry alive.
This is the tension that runs underneath everything. npm was a commons, a shared space where anyone could publish code for free. npm was also a venture-backed startup that needed to generate returns for its investors. Schlueter held both of these truths simultaneously and believed they were compatible. On March eighteenth, twenty sixteen, that belief was about to be tested.
Schlueter wrote to both Stratton and Koculu. His ruling was that the kik package name would be transferred to Kik Interactive. His reasoning was straightforward, most users encountering a package called kik would reasonably expect it to be related to kik dot com. npm's dispute resolution policy, which was vague and gave broad discretion to npm's staff, allowed this. The policy was loose enough that Schlueter could have ruled either way. He ruled for the company.
Koculu wrote back on March twentieth. He said he believed he had the right to delete all of his packages. And here is the detail that did not become public for eight years, until Koculu finally broke his silence in a blog post in June twenty twenty-four. According to Koculu's account, Schlueter, the man who had just ruled against him, provided him with a script that would remove all of his modules at once. If true, npm itself gave him the tool to do what he did next.
In his twenty twenty-four post, Koculu described this as evidence of condescending attitudes toward developers. The platform sided with the corporation, then handed the developer a button that would break the platform. The irony is almost architectural.
On March twenty-second, a Tuesday, Koculu was at his desk in the Presidio building at Lucasfilm. He ran the script. All two hundred and seventy-three packages vanished from npm. He stepped away from his desk for a moment, and within ten minutes a friend messaged him to say it was trending on Twitter.
Left-pad was a function that pads the left side of a string with a character until it reaches a desired length. Give it the string "five", tell it you want ten characters, and it returns "five" with six spaces in front. The source code was eleven lines of JavaScript. Before twenty seventeen, JavaScript did not have a built-in way to do this. The language simply lacked a string padding method. So someone packaged those eleven lines, published them to npm, and the ecosystem said, great, I will use that instead of writing my own.
The reason this mattered was not that two and a half million developers needed to pad strings. It was that Babel, the tool that translates modern JavaScript so older browsers can run it, quietly relied on a chain of tiny packages, each one a single link. And one of those links was eleven lines long, written by a developer in a film studio, and it had just vanished. Nearly every React project in the world depended on Babel. And Babel could no longer build.
Shortly after two thirty in the afternoon Pacific time, npm's systems registered hundreds of failures per minute. The cascade was immediate and indiscriminate. Any project that ran npm install and had left-pad anywhere in its dependency tree, even five or six levels deep, received a four oh four error and refused to build. This was not obscure infrastructure. This was the build pipeline for a significant fraction of the JavaScript web.
Within about ten minutes, a developer named Cameron Westland republished left-pad under the same name. But npm needed a more definitive fix. At four fifty-five Pacific time, Laurie Voss, the CTO and co-founder of npm, took what he called an unprecedented action. He forcibly restored the original left-pad version zero point zero point three, the exact version the ecosystem depended on. Un-unpublishing, as he called it, had never been done before.
This is the first time we have ever restored a package that had been unpublished against the wishes of the package owner.
The total disruption lasted roughly two and a half hours. In internet time, that is an eternity.
The aftermath forced a conversation the JavaScript community had been avoiding. The ecosystem had embraced the Unix philosophy of "do one thing well" and taken it to a place that looked, from the outside, like parody. There is a package on npm called is-odd. It checks whether a number is odd. There is a package called is-even, which depends on is-odd and negates the result. David Haney wrote a blog post that went viral, titled "NPM and left-pad: Have We Forgotten How To Program?" The question felt rhetorical. The answer was more complicated than the outrage suggested.
The strongest defender of the micro-package philosophy was Sindre Sorhus, a Norwegian developer who maintained over eleven hundred npm packages with a collective two billion downloads per month. Webpack relied on a hundred and one of his packages. Babel relied on a hundred and forty-four. In his essay "Small Focused Modules," Sorhus laid out the case.
Lines of code, he argued, are irrelevant. What matters is containing complexity. Small modules are like Lego blocks. Our short-term memory is finite. When you import a small, well-tested module, you do not need to understand its implementation to use it. You trust the interface. He drew an analogy to the processor industry. Rather than every PC manufacturer building their own processors, the industry consolidated around specialists like Intel and ARM. Costs dropped. Innovation accelerated. Why should software be different?
And there was a technical defense even for the seemingly absurd packages. JavaScript will happily check whether a string is odd and give you a wrong answer without complaint. Numbers beyond the safe integer range produce incorrect results for modulo operations. The is-odd package adds type checking and bounds checking that protects against these edge cases. Whether that justifies a separate npm package is the entire debate in miniature.
On the other side, Rich Harris, the creator of Svelte and Rollup, wrote "Small modules: it's not quite that simple." He pointed out that when Babel six was rearchitected into many tiny modules, it became, in his words, completely unusable, taking about three seconds to start up. If you use semantic version ranges for your dependencies, changes from deep in your dependency tree filter through to your users in ways that often result in breakage.
The debate has never been fully resolved. Both sides had real arguments. What everyone agreed on was that the system was fragile. The question was whether the fragility was a necessary cost of modularity or a sign that the philosophy had been taken too far.
The left-pad incident happened while npm was a startup trying to figure out how to make money from a commons. Understanding that corporate arc makes the incident land differently.
npm, Inc. was founded in twenty fourteen. The seed round was two point six million dollars. The Series A brought the total to about ten million. The company's pitch was reasonable. The registry was growing exponentially. Someone had to pay for the servers, the bandwidth, the security. Donations would not scale. A company could.
But the company needed revenue, and revenue meant enterprise features, and enterprise features meant npm had to be friendly to corporations. When Kik Interactive came knocking with a trademark claim, npm had to choose between a solo developer with a personal project and a company with two hundred million users and, presumably, the kind of money that could become a customer. Schlueter's ruling was legally sound and probably commercially prudent. It was also the moment the commons stopped feeling like a commons.
The corporate journey continued. In twenty eighteen, npm acquired the Node Security Platform. In late twenty eighteen, a new CEO named Bryan Bogensberger was brought in. Twenty nineteen was a year of turmoil. There were surprise layoffs handled badly. The CTO, CJ Silverio, was fired by text message after clashing with Bogensberger over crunch culture. The co-founder Laurie Voss departed. Bogensberger was asked to leave by the board that September.
In March twenty twenty, GitHub announced the acquisition of npm. GitHub was owned by Microsoft, which had paid seven and a half billion dollars for it in twenty eighteen. The terms of the npm deal were never disclosed, but the company's pre-acquisition valuation was approximately forty-eight million dollars. npm went from an open source project created by a vacuum cleaner salesman to a subsidiary of a subsidiary of the largest software company on earth.
Schlueter moved on. By twenty twenty-four he was building vlt, a new JavaScript package manager and serverless registry, co-founded with two former npm colleagues. A man who built the registry, ran the company, made the ruling that led to left-pad, provided the deletion script, and sold the company to Microsoft was now building a competitor to the thing he created. Open source has a strange sense of narrative arc.
If left-pad was about fragility, the event-stream incident two years later was about trust. And it starts with a man living on a self-steering sailboat.
Dominic Tarr is a New Zealand programmer whose website is titled "cyberhoboing with dominic tarr." He has over six hundred repositories on GitHub and more than four hundred packages on npm. He was one of the key figures in the early Node.js streaming ecosystem, and he created Secure Scuttlebutt, a peer-to-peer social network protocol designed to work offline and sync through local networks, the kind of system you design when you live on a boat and connectivity is not guaranteed.
One of his many packages was event-stream, a tool for working with Node.js data streams. It was downloaded about two million times a week. But Tarr had moved on. He was no longer interested in maintaining it. When someone showed up offering to help, he said yes.
That someone used the name right9ctrl. Starting in August twenty eighteen, this person made a series of innocuous contributions to the event-stream repository. Upgraded some dependencies. Added examples. Built trust slowly. Then on September ninth, they pushed a commit adding a new dependency called flatmap-stream.
The initial version of flatmap-stream was clean. A month later, on October fifth, a new version appeared. The malicious code was hidden in the minified source of the npm tarball but was not present in the GitHub repository, a deliberate evasion of code review. The attack was so precisely constructed that it borders on elegant.
The payload had three stages. Stage one read encrypted data from a file disguised as a test fixture. Stage two used an environment variable that npm sets automatically, the package description of whatever project imported it, as a decryption key. The only description that would unlock the payload was "A Secure Bitcoin Wallet," the description of Copay, a Bitcoin wallet application made by a company called BitPay. Stage three checked whether the wallet held more than one hundred Bitcoin or one thousand Bitcoin Cash. If it did, the malware harvested the private keys and sent them to a collection server.
If you were building anything other than Copay, the malware did nothing. It was a sniper rifle disguised as a garden tool, sitting in a dependency tree downloaded two million times a week, waiting for one specific target.
The attack went undetected for forty-seven days. On November twentieth, a computer science student at California State University named Ayrton Sparling, who went by FallingSnow on GitHub, spotted the backdoor and opened an issue on the event-stream repository with the title "I don't know what to say." A developer using the handle maths22 reverse-engineered the payload by downloading a list of every npm package that depended on event-stream, trying each package description as a decryption key until one worked. The identity of right9ctrl was never determined. They deleted their accounts on both GitHub and npm after discovery.
When asked about it, Tarr wrote a statement that became one of the most quoted texts in the open source sustainability debate.
One time, I was working as a dishwasher in a restaurant, and I made the mistake of being too competent, and I got promoted to cook. Maintaining a popular package is like that times a million, and the pay raise is zero. If it's not fun anymore, you get literally nothing from maintaining a popular package.
He proposed two solutions. Pay the maintainers. Or share responsibility by participating in the maintenance of your dependencies. He noted these were not mutually exclusive. Neither has been broadly adopted.
Three years after event-stream, in January twenty twenty-two, another maintainer made a different kind of statement. But to understand what Marak Squires did, you need to understand what had happened to him first.
Squires was a software developer living in Astoria, Queens. He maintained two widely used npm packages. Colors.js added color formatting to terminal output and had twenty-three million weekly downloads. Faker.js generated fake data for testing, random names, addresses, phone numbers, and had two and a half million weekly downloads. He was also, according to neighbors, an early Bitcoin investor, though no one could confirm this independently. What the neighbors consistently said was that he kept to himself. Blinds mostly shut. Little to no interaction with anyone.
On September fifteenth, twenty twenty, firefighters responded to a blaze at a home on Nineteenth Street near Twenty-fourth Avenue in Astoria. Squires, thirty-seven, was the first-floor tenant. A box near his stove had caught fire. He tried to toss it and it landed in his living room, spreading the flames. Neighbors saw him jumping from a rear window before emergency responders arrived. He appeared erratic and combative, with burns on both hands. He was transported to a Manhattan hospital, described as emotionally distraught.
Hours later, the landlord found something else in the apartment. Inside a crate, investigators discovered as much as forty pounds of potassium nitrate, along with magnesium powder, sulfur powder, copper powder, aluminum powder, metal containers, hobby fuses, mixing cups, and printed bomb-making and survivalist materials, including a book on how to make a bomb. The NYPD Bomb Squad said the materials were precursor materials but nothing that had been assembled. The NYPD, FDNY, FBI Joint Terrorism Task Force, and ATF all became involved. Squires was charged with reckless endangerment.
About a month later, Squires posted on Twitter that he had lost everything in the fire and requested donations. Open source community members who knew his work donated generously. He had an Open Collective page. The outcome of the criminal charges has never been publicly clarified.
In November twenty twenty, Squires posted on GitHub that he would no longer support Fortune five hundred companies with his free work.
Take this as an opportunity to send me a six figure yearly contract or fork the project and have someone else work on it.
Nobody sent the contract.
On January fourth, twenty twenty-two, Squires published a new version of colors.js. It contained an infinite loop that printed the word "liberty" repeatedly, followed by streams of garbled characters and an ASCII drawing of an American flag. He published faker.js version six point six point six with similar sabotage. The README was replaced with a single line: "What really happened with Aaron Swartz?"
The Aaron Swartz reference was not random. Swartz's death in twenty thirteen, while facing federal charges for downloading academic papers from JSTOR, had sparked global outrage over the criminalization of digital activism and prosecutorial overreach. It was a genuine tragedy that the tech community still mourned. But Squires twisted that tragedy into something else entirely, posting conspiracy theories connecting Swartz's death to Jeffrey Epstein's associate Ghislaine Maxwell, claiming Swartz was murdered after discovering child abuse material on MIT servers. This is a theory with no credible evidence, associated with the QAnon movement. Multiple people who interacted with Squires during this period described him as going through mental health problems.
Thousands of projects broke, including Amazon's Cloud Development Kit. npm reverted both packages to their last stable versions. GitHub suspended Squires' access to all of his repositories, both public and private. The community forked faker.js, and the community-maintained version became the canonical replacement.
As recently as February twenty twenty-five, Squires was issuing legal threats against the forked faker.js maintainers, demanding his name be restored to the license file. A person whose apartment contained bomb-making materials, whose open source protest invoked conspiracy theories, and whose actions broke thousands of projects was still, three years later, fighting over attribution in a license file. The story does not resolve into a clean lesson. It just continues.
After left-pad, npm introduced new policies that still exist today. If a package version is older than twenty-four hours, you can no longer unpublish it yourself. You have to contact npm support. If any other published package depends on yours, you cannot unpublish without going through support. When a package is unpublished and has known dependents, npm creates a security placeholder to prevent the name from being hijacked.
These rules exist because of one Tuesday afternoon in March. Every developer who has ever tried to unpublish a package and been told they cannot has left-pad to thank. But the rules created new problems of their own. In December twenty twenty-three, someone published a package called "everything" that listed every other public npm package as a dependency, creating millions of transitive dependencies. Because the post-left-pad rules prevented unpublishing any package that another package depended on, and "everything" depended on every package, the rules designed to prevent deletion were now preventing deletion. Even the author of "everything" could not unpublish it. npm had to intervene manually.
The numbers tell a story too, though not the one you might hope. npm had roughly three hundred thousand packages in March twenty sixteen. By June twenty nineteen it crossed one million. Today it has over three point one million. The average dependency tree stretches ten or more levels deep. Academic research from twenty twenty-four found that over fifty percent of dependencies are bloated, meaning they are pulled in but never actually used by the project that depends on them. Thirteen percent of direct dependencies are bloated. Fifty-one percent of indirect ones.
In September twenty twenty-five, the United States Cybersecurity and Infrastructure Security Agency issued an alert about a widespread supply chain compromise affecting the npm ecosystem. Over a hundred and fifty thousand packages were discovered connected to a blockchain token-farming scheme called Tea, where people published garbage packages to game download metrics for cryptocurrency rewards. A hundred and seventy-five malicious packages were found in a separate credential-harvesting campaign.
The micro-package culture did not change. The dependency trees got deeper. The attack surface got wider. The conversations after each incident sound the same. We need better funding for maintainers. We need better security review. We need fewer dependencies. And then the conversation fades, and the next project starts with npm install, and hundreds of packages fly by in the terminal, and nobody checks who is behind them.
Left-pad might not appear in your dependency tree directly. Maybe you write Python, not JavaScript. Maybe you have never touched Node.js. But if any part of your stack uses a frontend build tool, a documentation generator, a linter, or a CI pipeline that touches JavaScript, then somewhere beneath it is npm, and somewhere in that dependency tree are packages you have never looked at. The philosophical ground is the same.
And the pattern is universal. Python has had its own supply chain incidents. PyPI has had its own disputes over package names. The same dynamics, solo maintainers, corporate pressure, insufficient funding, vast trust assumptions, exist in every package registry. npm just happened to demonstrate them first, loudly, on a Tuesday afternoon, because of eleven lines of code that padded strings.
Left-pad is still on npm. It is marked as deprecated. The readme tells you to use String dot prototype dot padStart instead, the native JavaScript method that was added in ES twenty seventeen, the year after the incident. The function that broke the internet is now built into the language. It still gets about a million downloads a week from legacy dependency trees that have never been updated.
Koculu left the United States after the incident. He spent a year traveling through Morocco, Jordan, Turkey, and Indonesia. He hiked the Lycian Way along the Turkish Mediterranean coast. He described left-pad as a death and rebirth, the part of him invested in open source dissolving, replaced by a passion for building companies. By twenty twenty-four he was a startup founder. He does not maintain any npm packages.
Schlueter built npm, sold it to Microsoft by way of GitHub, and is now building a competitor to the thing he created.
Tarr is still on his sailboat.
Squires is still sending legal threats to the people who forked his abandoned code.
And every package you install was built by a person with a name, an opinion, and a breaking point. The thing about breaking points is that you never know where they are until someone reaches one.
That was episode one.
Here is something you can try after this episode. Open a terminal and type npm info left-pad. The ghost is still there, marked deprecated, still getting a million downloads a week from dependency trees nobody has cleaned up. Now try something else. Pick any project you have that uses Node, navigate to its directory, and look inside the node underscore modules folder. Count the directories. A typical project has hundreds, sometimes thousands. Each one is a package written by a person you have never met, installed without you ever asking for it, sitting in your project right now. You do not need to do anything about it. Just look. Know what is underneath.