Eval all the strings! - Hardened JavaScript

GithubProject website

This talk is about SecureEcmaScript and Compartments which are TC39 proposals, and I'm working on tooling to make these concepts usable with people championing those proposals.
This is a first-hand account of the future of JavaScript security.
SES + tooling (LavaMoat or Endo) is making limiting access to network, fs, core modules or globals possible on a per-package basis.
I want to show how they work, what possibilities they open and how to make that future happen today with some effort.
To me this is the final step in securing npm supply chain - even if a package gets taken over by bad actors, it won't be able to hurt me.


I'm Zibi, now Guter, it's in the corner and in the middle. Would you take a string I gave you and run it in your application? That's cool. Raise your hands if you would. No really? Okay, would it help if I put it in the tar.gz file? Because that's what npm packages are and they're glorious, don't get me wrong, but they're also unsanitized inputs from the internet that you run in your application. And we love them. I'm installing npm packages all the time, that's the main thing I do at work. But what if some of them are not great? And I don't mean lousy packages, I published a bunch of lousy packages, nothing bad happened, but actually malicious, dangerous packages. What then? Well, you can wait for someone to find out that the package is malicious, submit it somewhere and then npm audit is going to tell you a few weeks after you shipped your app to production with this package in your dependencies. That works already. You can go with socket dev which has a much tighter feedback loop but it just tells you that stuff is suspicious and you have to investigate. So do you have time to read your dependencies? I don't know. Oh, I don't have a network connection. That's funny. Yeah, there was a logo here. Okay, but with LavaMote, you can be proactive instead of reactive and that's a great thing, being proactive instead of reactive, let me see if I can refresh this now. Okay, I have a demo. I can show you what it does. This is a very brief version of the demo, sorry, there's much more steps, but I have an app here that's using a package to get very valuable data and then it's sending it to a different server with some authorization that's coming from environment variables. Okay, if I run it, I have this local host server running and it's going to pop up the result. Okay, that's what it does. It gets stuff. So what's the package doing? The package is getting this valuable information from somewhere and sending it over. Okay, now what if the maintainer got bored and handed over the package to someone else who had some bad intentions? Okay, so see, live coding, barely any typing. So if they grab your precious secret and send elsewhere, what would happen? Well, they would get it. Okay, so the other server just got the secret, right? And the stuff still works. Okay, so what if we want to prevent it? That's where Lava Mode comes in and Lava Mode generates a policy for you which contains information like this package can access fetch and buffer for other versions of that package that I wanted to demo. Okay, so with Lava Mode, if I do, I have Lava Mode wired as npm test. I'm going to run it and it's going to say this. It's slightly garbled but it says process did not exist. Process was undefined actually. For this package only, so you can use process in the main app or other packages but this package doesn't have access to it. Okay, so let's do some more hacking. Have you heard of prototype pollution? There was a chance to hear about it today. So if I take object prototype and I define a setter as authorization, a field on that, and I pass authorization header to fetch, fetch is going to call my setter that I set on the global prototype. How funny. Okay, so this is still going to work under regular node. And then with, yeah, I got the bearer and the secret. But if I run under Lava Mode, I'm going to get an error that says cannot define property authorization, object is not extensible. Lava Mode is also using a technology behind the scenes called lockdown that locks down everything and it's impossible to tamper with the javascript environment itself. Okay, going back here. So what's the magic? It's called hardened javascript. Lets you isolate. In our case, we're using it to isolate each dependency within the same process. There's no other context or realms involved in all of this. It has compartment, lockdown, harden, yeah, let's skip over that. It's becoming part of a language eventually. It's an early stage proposal right now, but coming from people who are responsible for stuff like CommonJS, promise in the language, et cetera. If you want to know more, these links are available and I'm offering to help you set up Lava Mode with your project if you get in touch early enough. But I promised I'll evo all the strings, right? So I have one more demo that's, oh, I'm not over time yet, cool. I made this thing, I used this technology to make this thing where I can run any code and get prompted synchronously for everything it reaches for. So I took actual malware from npm. It's already removed, but it was there. It's, yeah, let's run it. So it's using eval and a bunch of other stuff a bunch of times. And I have to agree to this, but I went through this scenario a bunch of times. So it has four levels of obfuscation. I tried to deobfuscate it and it didn't work after the obfuscating, very clever malware. And now it reveals itself to me. So you want to know what the file looks like? This is the original file I'm running in my tool. And it says require FS. Okay, what else do you require? HTTPS, child process, cool. It tries to exec something and then it requires axios and then it reaches for process. Let's give it a fake process. Env, local app data, okay, okay, I know what you're looking for, cool. Let's give it a string that I can recognize and then it does read or a dir sync on that and tries to analyze it. Then it calls task list process, okay, nice. And then it sends a post to Discord. I didn't have to deobfuscate the file. It revealed itself to me. Thank you. Lava mode. All right. Thank you. All right. Thank you.
8 min
14 Apr, 2023

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Workshops on related topic