TL;DR: Some dude gave away his popular Node.js repo to a hacker, and that hacker added code to it that can steal your bitcoin wallet! Wanna know how that happened? Keep reading….
Short of a month ago, something quite impactful happened for the Node.js community, you might’ve missed it since it only affected some projects related to crypto-currency.
But if you read into what happened, you’ll realize that the affected projects or even the affected area of software development is not the actual victim, this attack actually put a dent in the world of Open Source.
Let me explain.
What happened though?
Let’s start at the beginning because now that some time has passed and the main affected parties have had the chance to fix the issue, there’s been a lot of misinformation going around (this is Internet after all).
A lot of people are calling it “the latest npm breach” or “a hacker attack on npm”, but that’s one of the things they’re getting wrong. This was not directed at npm (npm being the Node Package Manager every Node.js developer uses to manage what packages are included in their projects). This was a very focused attack on one specific entity: a package called copay-dash.
You won’t be able to find it in npmjs.com but if you simply try to install it, you’ll be able to do so, although you’ll also see the following interesting message while you do it:
That message lets you know you should not trust this package, although the culprit is misspelled. The actual package that was affected by the evil party was not “event-steam” but rather “event-stream”. Let’s look at how this happened.
The best attacks are the ones you don’t see coming, am I right? In this case, the attacker, who we’ll eventually learn is called right9ctrl on the interwebs (as expected, their real identity remains a mystery), affected a different package, one that has well over two million downloads a month, in the hopes that it would be used in the same project as the copay-dash package.
If you happen to be so unlucky as to find yourself using both in your project, the malicious code would run and it would try to steal your public keys for your bitcoin wallets, sending them to a host server in Kuala Lumpur.
The attack was crafty, it didn’t go after the original target, rather it affected a secondary, optional package, but one that was massively used by the community.
The question now remains, how did this hacker gain access to event-stream’s code and how in Eich’s name did they manage to infect it as they did?
The answer to that question is, sadly, they gained access simply by asking for access. You see, event-stream is just one of the thousands of Open Source projects out there being used daily and maintained (and this is key here) for free by developers everywhere.
So when the owner of this package was approached by a willing contributor with a Pull Request (a request for merging a given improvement into the original source code), that person did not really think twice about it. The owner of this project is called Dominic Tarr and he has said it several times already, he had no interest in maintaining this code anymore, he was not using the library anymore and there was nothing he was getting out of maintaining it. So he didn’t just merge the pull request, he also gave ownership of the project (although not the Github repo) to the hacker.
Yes, and just like that, the hacker had gained control over the ability to push new code and overwrite the version of the package, forcing most developers to think they needed to update their local copies.
You can see the commit history for event-stream and you’ll notice the last 16 commits were made by the same user, but there is one that is crucial, the one where the hacker added a new dependency. You see, instead of directly modifying the event-stream library, this user created a different package, one called flatmap-stream and added it as a dependency, basically adding compatibility with a new tool, knowing (most likely) that the developers would not care to look and read through the code of this third-party library, they would only care about the changes made to their source code (if that). You can see the commit details here.
That was the extent of the “hack”, after that, a couple of commits were pushed in order to force version updates and other minor details, but nothing major, the damage had already been done.
Sadly, access to the malicious repository has been revoked, and now if we try to visit flatmap-stream’s repository or npmjs.com page, all we get is the following message:
This package name is not currently in use, but was formerly occupied by another package. To avoid malicious use, npm is hanging on to the package name, but loosely, and we’ll probably give it to you if you want it.
You may adopt this package by contacting firstname.lastname@example.org and requesting the name.
Although not officially available, the code can be found in several blog posts around the web (here for instance), it’s not that long, but it works by actually decrypting itself, and injecting the malicious code into Copay’s library. However, this is not the focus of this article, far from it actually.
What went wrong?
To understand why this happened, we need to look at what the owner (and the person who everyone pointed at once this problem was discovered), Dominic Tarr had to say:
Hey everyone — this is not just a one off thing, there are likely to be many other modules in your dependency trees that are now a burden to their authors. I didn’t create this code for altruistic motivations, I created it for fun…. I think most of the small modules on npm were created for reasons like this. However, that was a long time ago…I’ve shared publish rights with other people before. Of course, If I had realized they had a malicious intent I wouldn’t have, but at the time it looked like someone who was actually trying to help me. Since the early days of node/npm, sharing commit access/publish rights, with other contributors was a widespread community practice. …open source is driven by sharing!…
You can read the full statement and the conversation it started here and of course, the bolded parts and the trimmed bits were added by me, to make a point. The full post has all of the details behind his reasoning, but you get the gist by simply reading the paragraph above.
Essentially, the hacker lunged at the soft underbelly of Open Source. The fact is maintaining Open Source packages, especially popular ones can be a burden, and burnout in Open Source developers is extremely and alarmingly common. They work their backs off to get quality code out there, so others can profit from their work, without getting anything in return. Or without direct retribution at least, since one could argue maintaining popular packages, is a great calling card when introducing yourself to people in our industry. It reaches a point where even that is not enough and developers just abandon their work. And who can blame them?
Is it their fault if their code is compromised or is it the fault of the one using the library without checking twice? If you think about it, our industry is unique in the sense that we share our experience with others for free. This doesn’t always happen, in other jobs. But in software development, that’s not the case, those with the know-how share it, they write blog posts, they share their code publicly. Think about that for a second. The Open Source movement transformed our industry to the point where we collaborate and grow off of each other’s achievements.
But today we’re reading about the dark side of the Open Source movement (and not for the first time), we’re learning that not everything is perfect and that even the best intentions might fall short if there isn’t a system behind them that can support them. Open Source developers can’t keep working like they do today, we’ve reached a point where a single change in a small public module can affect millions of users and can be used to steal sensitive information, we need Open Source 2.0.
Whatever that means, it’ll have to come in the form of a support system for the developers that will help avoid burnout. Two quick ideas that everyone is keen to suggest are:
- Pay the developer. We should find a way to formalize the means to pay developers for their work. But who’s paying? Will we force everyone to pay? Wouldn’t that go against the actual meaning of Open Source? There is some merit to this idea, but it needs to be properly implemented or it will cause more harm than good.
- If you’re using Open Source, get involved. This one might sound better, but I think it’s equally hard to implement. Just like we’ve managed to create a utopian-like industry where everyone is willing to share knowledge with each other. The ones that actually do so, and spend countless hours perfecting their craft and maintaining their code are but a small percentage of the industry. I don’t have the numbers, but I would be willing to bet most of the developers out there simply take and don’t give back. This is not a simple problem to solve either, why don’t they give back to the community? Is it because they don’t know how to? Is it because they don’t care to? Do they actually understand how big of an impact they would cause if they were to share the bug they found in that library they’re using?
I don’t have the answer, but I feel like it could come from a mixture of the two points above. The whole problem though, can be summarized to a quick sentence (it doesn’t make it easier to come up with a solution though, but at least it’s easier to explain to others): Developers need to be educated in Open Source, everyone needs to understand that they can give back and should do so whenever possible. Be it in the form of a bug fix, a published tutorial, a video review or any other way you can think of, but it should be the responsibility of the many and not the burden of the few.
Do you have a solution for developer burnout? What would you suggest to improve the life of Open Source maintainers? Leave your comments down below or tweet me at @deleteman123
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.