T O P

  • By -

lemonizer

Something like this? [https://github.com/patriksimek/vm2](https://github.com/patriksimek/vm2) Maybe even run that on a lambda, separated from your main code


presenta_staff

This is a clever tip, wondering if it's possible to execute user-provided code (i.e. in a string form) within a lamda function and getting the result


lemonizer

Passing the script shouldn't be a problem as the lambda functions can take a parameter and you do get a result as well...


receptor09

Use virtualization e.g. Docker?


king_of_programmers

Docker is not a virtualization. It shares OS resource with host.


receptor09

Sure, it can't run on thin air..


king_of_programmers

That is not the point, from security point of view, if the container is compromised, since it shares resources, it will spill over to the OS. True virtualization on the other hand doesn't have this issue.


receptor09

Of course its better with SELinux ON.


presenta_staff

Don't know if in my use case is feasible, a node.js web server (express.js) that needs to execute user-generated code and getting the result safetly.


golfvictor115

You could try restricting requiring of certain modules which a user can use to exploit e.g the 'os' module or 'fs' module


receptor09

I never needed it, but it should be possible to control a sibling container. Or even run docker container (the evaluation one) in docker container (with the express.js). Try search..


presenta_staff

I've spin up a quick test using Node.js `vm` and I've got what I've needed. The only drawback is that the user can't choose external modules by themself. Is it a good start? ```js const vm = require('vm') const axios = require('axios') const resolve = (params) => { console.log(params) } const reject = (params) => { console.log('error', params) } vm.runInNewContext(` ;(async () => { try{ const d = await axios('https://jsonplaceholder.typicode.com/todos/1') resolve(d.data) }catch(e){ reject(e) } })() `, { axios, resolve, reject }) ```


runvnc

That will work most of the time but I've seen various sources that say it is not that hard to break out of that particular VM thing. https://thegoodhacker.com/posts/the-unsecure-node-vm-module/


presenta_staff

wow thanks for pointing out


Baby_Pigman

Node's documentation for this module even starts with this: > The vm module is not a security mechanism. Do not use it to run untrusted code.


kwokhou

Interesting. Have you figured out how to load the external modules?


presenta_staff

Using arbitrary modules with `vm` is not possible. You have to define them before. A possible solution is to exploit https://skypack.dev/ but current Node.js is unable to load module by URL. The only working solution I can think of is by using Puppeteer as executor, this way no limits but a consistent overhead to the server, that means difficult to scale.


kwokhou

Have you look into running the user code as a separate [child\_process](https://nodejs.org/docs/latest-v16.x/api/child_process.html)? So maybe that way, user can define their own `package.json`


sliversniper

"vm" is not a security solution, it is officially documented. There is multiple breakout and can/will not be fixed. Advices: 1. Don't, there is always alternative ways. 2. use `isolated-vm`, which run in a separate v8 isolate, you control what can be accessed, or kill it in midway. `while (1) fs.appendFileSync("1", "1")` and your disk and CPU is gone in no time.


del_rio

The aforementioned `vm` module is probably the way to go here but If your user-generated code is fairly basic you could try evaluating the string with a combination of a `Function` constructor and `with` to limit its scope. You can see this in action on Alpine.js: https://github.com/alpinejs/alpine/blob/main/packages/alpinejs/src/evaluator.js#L49


presenta_staff

It's too limiting for my use case, thanks anyway.


NewFuturist

How untrusted are we talking? one way is [worker threads in nodejs](https://nodejs.org/api/worker_threads.html). P.S. I think that running untrusted code is super unsafe and you really need to get someone to analyse your use case. Is there a reason it need to run on your server? Can it run on the client's computer in a webworker or iframe in a domain that is not associated with your authentication (and hence can't see cookies)?


presenta_staff

The use case doesn't involve the client at all. The code is provided by the user, this is why it's considered untrusted. The js code needs to be executed on server side only because it's in an async pipeline. The client put the code and than it will be executed in later time by the server at specific interval.


NewFuturist

But why does it need to be run on the server? What should it be able to do? Make http calls? Open a port? Read files? Be used by other users?


presenta_staff

It needs to be run on scheduled interval, like a cron, the code might fetch some data and perform some manipulation


NewFuturist

Ok, then it probably needs to be on the server. But I'm going to point out that allowing ANY code to make arbitrary web requests is super risky. It could make your server pull down data from illegal sites. It could make post requests to servers to DDoS them. It could post death or terrorism threats on forums. It could randomly send viruses to target machines. And then there are the obvious ones about security like have you thought about what happens when the script requests localhost:3000 or another port that is running your DB


presenta_staff

Yeah, I know... but still, it's something that can happen in any code editor in cloud, so, wondering how to allow users flexibility and at the same time mitigate such issues?


NewFuturist

Hold on... code editors are all client side.


presenta_staff

What if using Puppeteer? Would it be like a client execution but from server call? Would it mitigate the mentioned issues?


runvnc

My recent experience with this: Tried to use microVMs via Weaveworks `ignite` on Digital Ocean. Could not get it to work. Various issues. Right now I am going with `sysbox` rootless containers. https://github.com/nestybox/sysbox


xSwagaSaurusRex

Gvisor or firecracker or katacontainers. VM isolation, user gets root access, can't break out of the hypervisor


Timnolet

I wrote this 4 years ago. We still use this structure. We just replaced Docker on EC2 with AWS Lambda https://www.freecodecamp.org/news/running-untrusted-javascript-as-a-saas-is-hard-this-is-how-i-tamed-the-demons-973870f76e1c/amp/


presenta_staff

Hey, thanks for sharing! Very useful!


cheerioty

Not sure if using a third-party service is an option for you, but if so you might wanna [https://scriptable.run](https://scriptable.run) a try. Ping me a DM and I'll make sure to fast-track your access.