Safely Running Untrusted Code in Node.js: Isolation Strategies & Performance
This article examines reliable and relatively reliable methods for executing untrusted JavaScript code in Node.js, comparing new Function, the VM module, and Worker Threads, discussing their isolation levels, memory and CPU limits, performance overhead, and extending to container and WebAssembly security solutions.
What scenarios need code isolation?
Common cases include:
SSR (server‑side rendering) where component code must run on the server.
Distributed scheduled‑task systems that execute lightweight user‑submitted scripts.
Rule engines that evaluate matching conditions.
Problems to solve
Typical challenges are:
Memory leaks caused by insufficient variable isolation.
CPU‑time limits, e.g., infinite loops or long‑running code.
Control of external resources.
Node.js code execution model
Node.js runs on a single OS thread with a single V8 isolate by default. An isolate is an independent V8 instance that includes its own memory management and garbage collector, and it is bound to an OS thread.
A context is a global object defined on the heap of an isolate. Multiple contexts can exist within one isolate and can safely access each other.
Specific solutions
new Function
const func = new Function(`console.log('hello')`).bind({});This approach is fast and scopes local variables to func, but it allows escaping to the global scope, e.g.:
const global = Function('return this')();
new Function('const global = Function("return this")(); return {global, a: this};').bind({})();Node.js VM module
The VM module (available since Node.js 0.3.0) provides better variable isolation than new Function.
const vm = require('vm');
const script = new vm.Script('globalVar = "set"');
const contexts = [{}, {}, {}];
contexts.forEach(context => {
script.runInNewContext(context);
});
console.log(contexts); // [{globalVar: 'set'}, {globalVar: 'set'}, {globalVar: 'set'}]Creating a context is relatively slow, which can affect performance for frequently executed code.
Node.js Worker Threads
Worker Threads (introduced in Node.js 10.x) create separate isolates, enabling multi‑threaded execution. They can be combined with the VM module for full isolation, but thread creation is expensive and communication is limited to data structures supported by the HTML Structured Clone algorithm.
Comparison of solutions
Solution
Variable isolation
Memory limit
Isolated isolation
Execution time limit
Async operation limit
new Function
Partial
❌
❌
❌
❌
vm
✅
❌
❌
✅
✅
worker threads
✅
✅
✅
✅
✅
Extension: Security
None of the above solutions provide strong protection against malicious code. Two higher‑level approaches are recommended:
Trusted containers
Use trimmed virtual machine monitors (e.g., AWS Firecracker) to achieve isolation at the hypervisor level.
WebAssembly containers
Compile code to WebAssembly and run it in a WASI‑enabled container, allowing control over instruction speed, memory usage, and external resource access. Current limitations include immature tooling and limited V8 support for fine‑grained control.
Community projects such as isolated‑vm also explore isolate‑based isolation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
