1. Introduction to npm packages
2. Dealing with Malicious npm Packages
We need to address the issue of malicious npm packages. Reactive tools like npm audit and SocketDev can help identify potentially malicious packages, but they require manual checking. Alternatively, Lavamote offers proactive runtime protections for your application. Imagine a scenario where a developer installs a build tool, and a malicious hacker inserts code into a dependency. This code can compromise sensitive information. To mitigate this risk, we need an app that can automatically detect such threats.
You know, we're installing npm packages, we're installing a lot of them. But what if some of them are not great? And by not great, I don't mean lousy packages, I published a bunch of lousy packages in my time. Nothing bad happened, but I mean actually malicious packages. This talk is going to be strictly about malicious packages.
How do we handle that situation? Well, there's tools that I call reactive tools. You can use npm audit or anything that goes through CVE reports, etc., and tells you that, hey, this package in your dependencies that has been in production for two months, someone reviewed it and found a problem with it. That package is actually malicious. Is that good enough? Probably not. Then there's SocketDev. SocketDev is this new thing where they use various ways of analyzing the packages automatically and come up with suggestions that, hey, this package, it looks like something's wrong with it. You should look it up, you should check what this package is doing. It looks risky. So SocketDev can tell you that even hours after the package has been published, because it's already analyzed. That's a big improvement. Although you have to do the checking yourself. Do you have time for that? Well, now you have to. What are the other options? Well, you can be proactive instead of reactive. And this is where Lavamote comes in. I'm going to tell you about Lavamote. Lavamote is a bunch of tools that together provide for protections for your application. But those protection happen at runtime instead of when you're looking up packages that you wish to install. Okay?
So how does it work? Well, let's go through the basics here. So imagine this developer guy. He wants to install a build tool for the application. What happens is one of the dev dependencies of his application, somewhere in the tree of dependencies of this build tool is controlled by a malicious hacker represented by a black hat and a hoodie, obviously. And what the hacker does, they put a bit of code in an existing package that was already relied upon. That code takes your GitHub token and sends it somewhere. Is that nice? That's not nice. So would you spot it? Well, it's unlikely that you read everything that you put in your dependencies. So instead, let's use an app for that.
3. Lava Mode and Policy Enforcement
And this is where Lava Mode comes in. Lava Mode does two things at this stage. It first generates a policy. So you run Lava Mode on your application. In this case, your application is the build process. So you run your build process through Lava Mode with a flag that says, oh, generate the policy automatically. And do you get a policy file that you can edit? Let's get to it in a moment. And then your actual script is not running purely in Node, but it's running in Node instrumented by Lava Mode. And Lava Mode is going to make sure that the policy that is set is going to be enforced.
What's that policy all about? This is the policy. This is a short bit of the content of one policy. So you have that eslint plugin, and it has a dependency that the hacker modified, and the use of HTTPS and process env will likely be detected. So it shows up in the policy. You can switch that to false. Or you can remove those items altogether from the policy, which means these are not going to be available. And what's great is the policy is enforced per package. So inside of the same process, inside of the same contexts, we have sandboxed each package separately in a way that you can decide which built-ins or which imports in general are going to be available to it and which globals are going to be available to it.
And on top of that, we can build the part of Lavamode that decides what can be accessed by whom.
Okay, and compartments, or to be more precise, everything behind the compartment implementation is going to become part of the language. Well, eventually, it's an early stage proposal. There's been a bunch of progress on virtualizing the module loading. This is happening in 2C39, and eventually we will get all of the bits that are necessary to build a compartment in the language itself. And these are being pushed by people who are responsible for bringing us the things like object freeze, use strict or promise. So I'm hopeful.
5. Introduction of Webpack Plugin and Beta Testing
We're introducing a webpack plugin for those who don't want to use the browserify ecosystem. Webpack is the most flexible built system, and after four tries, we made the plugin possible. We're opening our beta for testing, so please let us know if you encounter any incompatibilities. This is an open source project, and we want to provide support and fix any issues that arise.
So it got developed a few years back and is now been powering metamask integration with laugh mode for a while. So we can take that and use it right away, but we're introducing a webpack plugin for those of you who don't wish to stay in the browserify ecosystem or even get back to it because yes, yes I know browserify is kind of dated. It was great at the time, but now it's kind of dated. Webpack was the most flexible of the built systems that are currently used. So we went with that. And while it initially seemed impassable, but after four tries we got to a point where the plugin is actually possible. And we're going to open our beta, which is a trial run. So no guarantees for security and production yet, but we want to test it out on your project. And please let us know if you find any incompatibilities where your Webpack plugins get interfered with by our plugin. So please get in touch in the discussion thread. This is the only chance to get life support for the plugin without paying for it in any way because this is an open source project. And while we will probably not support everyone all the time, this is the time where we really want to be in touch with you and look at what you're doing and what trouble you get in so that we can fix it for everyone in the future, okay?
6. Exploring Lavamote's Behavior
Let's take a look at what Lavamote does live. It's a simple application that imports a package called Cookie Monster. The application sets a cookie, prints out the cookie and location host, and calls for a random quote from CookieMonster. The TypeScript file is also included, and the whole thing is built with webpack. The CookieMonster package is allowed to use fetch, math, and encode URI. However, it also attempts to steal cookies by sending them to a server.
So let's take a look at what Lavamote does live. So this is a very simple application. For the sake of brevity, what it's doing is it's importing a package I made called Cookie Monster. By the way, don't look for this package on NPM. It's a malicious package and publishing malicious stuff to NPM is not a good idea. I mean, I've been banned from NPM before. So let me tell you, you shouldn't do it.
And then there's another package just to prove that you can import some CJS old package and it's still gonna work. There's a bit of TypeScript that's being imported. This whole thing is getting bundled and sent into the browser for running. What does it do? It sets a cookie. And then it prints out the document cookie and the location host for context. And then it calls for a random quote from CookieMonster. And the CookieMonster gives us a quote, a famous quote from CookieMonster, it's always fun. We pass it through leftPad because why not? And then we get a reaction from the TypeScript file so that we know that the TypeScript is working. And this whole thing is built with webpack. So we have app.js as entry point. It gets bundled, and it has some plugins that webpack normally uses. But most of all, it has the ScoreTrop plugin. And we pass the policy in here. This could obviously be loaded from a file because why not, but we're passing the policy here. leftPad is not allowed to reach for any globals, that's normal because leftPad is not relying on any globals. And now, CookieMonster... We allow CookieMonster to use fetch, math, and encode URI. So these are the globals that CookieMonster is going to successfully access.
Okay, now let's look at the CookieMonster. CookieMonster is giving us a random quote from a bunch of quotes that are available, but then also attempting to steal our cookies. Well, is a CookieMonster, what did you expect? So yes, it's going to run a fetch and send your host and your cookies to a server to use them in the future. And this is not the best thing to happen to your cookies, mind you. Let's take a look at the behavior of this application.
7. Analyzing Application Behavior and Beta Testing
Let's take a look at the behavior of this application. So I've built this application with and without the Scoretrot plugin, and now I can show you what it's like. So here we are on a page with dev tools open where Scoretrot plugin was not involved. Okay, let me reload the page and show you what happens. So we're on localhost name, chocolate chip is what we have as cookies. We get the quotes and we also get an error because cookie monster was not too discreet with sending this request, but you can see that the request contains our cookie that has been stolen. Meanwhile, if we run with lav modes, you can see that we get undefined. Why do we get undefined? Because, location and document were not listed in the policy. So they do not exist for cookie monster. Meanwhile, our application was successfully accessing them for printing out in the console. That's pretty much what happens here. We're controlling that, not the cookie monster.