0
\$\begingroup\$

I am making a sandbox environment for javascript. For this I create a webworker with this function:

(self is a webworkers global context)

(() => {
   Function("\"use strict\";\nlet self,fetch,globalThis;(async()=>{try{"+arbitrary_code+"}}catch{})").apply({});
   return;
})();

With this, people are only able to use vanilla javascript with no access to any browser api's. Is there any way to defeat this sandbox, is it secure enough?

\$\endgroup\$
2
  • \$\begingroup\$ You have little control over the execution environment, so any vulnerability, in any browser, can possibly be exploited. \$\endgroup\$ Commented Nov 27, 2022 at 16:23
  • \$\begingroup\$ FWIW a simple new Function('return this')() would escape this and expose the global context. \$\endgroup\$
    – Kaiido
    Commented Jul 11 at 2:46

2 Answers 2

1
\$\begingroup\$

If you want to do something similar to online JavaScript sandboxes, where arbitrary code be executed while limiting the damage that code can cause, what you do is run the code in/from an isolated page inside a frame on a different domain. Doing it this way lets you take advantage of several safeguards that browsers come built-in:

  • iframes have attributes that let you lock down what the page inside have access to (see sandbox and referrerpolicy).
  • iframes are bound to the Same-Origin Policy, preventing the framed content from a different domain from reaching into the embedding page.
  • You can set Content Security Policy rules to limit what the parent and the framed page can do (e.g. prevent the embedded page from being embedded elsewhere, prevent parent page from embedding a page from somewhere else).
  • Because the page is on a frame in a different domain, it's considered a third-party context and built-in browser protections like partitioned storage APIs kick in.

This does mean your page's domain is different from the frame's domain, and that your code would have to be transported between domains (e.g. store the arbitrary code in a shared DB for the sandboxed domain to fetch and render).

And as mentioned by KIKO Software, this doesn't prevent any other security issue outside of this scope (e.g. browser exploits, social engineering, security flaws on the embedding page, malicious extensions, etc.).

\$\endgroup\$
1
  • \$\begingroup\$ This is a really good option, and even allows me to mostly keep my existing code. Should also be easier on server-side rendering, and I would no longer have to use eval/Function! Thank you! \$\endgroup\$
    – Nightfall
    Commented Nov 29, 2022 at 13:08
-1
\$\begingroup\$

If you really want a water tight sandbox environment then you should look at using wasm. You can even run it in a webworker

There is (or should be) no way out of a wasm interpreter call without going through the functions you set up for communicating back to the wider code. There is no other way to hand control back over. The only real danger is when the wasm module puts itself into a infinite loop, but that's something your code didn't defend itself from either.

There are js to wasm compilers though there are better languages to use as the source language for this.

\$\endgroup\$
1
  • \$\begingroup\$ Great awnser, thank you! I looked into wasm for a while, but it has some issues specific to my project. That is why I ended up using webworkers in the end. \$\endgroup\$
    – Nightfall
    Commented Dec 1, 2022 at 8:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.