Skip to the solution
HardLow-Level Design7 min read

What is the 'vm' (Virtual Machine) module and when would you use it?

404 views

The problem

Question presented to candidate: "You need to evaluate a small, user-provided expression β€” a formula in a spreadsheet-like feature, say β€” without exposing your application's own variables and functions to it. Does Node's vm module actually give you that isolation, and is it a full security guarantee?"

What a strong answer should cover:

  • Node's built-in vm module compiles and runs JavaScript within a separate V8 context, with its own global object, distinct from the calling code's global scope β€” vm.createContext(sandbox) turns a plain object into that separate context's global scope.
  • πŸ“Œ Verified, not assumed: a real vm sandbox genuinely could not see a variable set on the real Node global (typeof outerVar returned "undefined" inside the sandbox), and a var declared inside the sandbox did not leak out to the real global (confirmed undefined there) β€” it appeared instead as a property on the sandbox object itself. This is genuine two-way separation, not merely a naming convention.
  • A precise, important limitation, stated explicitly rather than glossed over: vm is not a complete, airtight security sandbox for genuinely untrusted code β€” Node's own documentation is explicit that it provides isolation of variable scope, not a guarantee against denial-of-service (an infinite loop inside a vm context still hangs, unless externally timed out) or every possible context-escape technique that has been found over the years.
  • The realistic, correct use cases: evaluating a known-shape, restricted expression (a spreadsheet formula, a simple templating expression) where the input is not fully adversarial, or building developer tooling (a REPL, a code sandbox for a trusted internal tool) β€” not running genuinely untrusted, potentially hostile third-party code with security guarantees riding on vm alone.
  • For genuinely untrusted code needing a real security boundary, the correct answer is a stronger isolation layer β€” a separate OS process (with its own resource limits) or a dedicated, purpose-built sandboxing product β€” not vm used in isolation.
  • A precise answer connects this directly to the dedicated eval()-security-risks question: vm is the more structured, partially-isolated alternative to a bare eval(), but the word "partially" is load-bearing β€” it narrows the blast radius of variable/scope access, it does not eliminate every risk a fully adversarial input could pose.

Clarifying questions expected:

  • "Is the input genuinely adversarial/untrusted, or a restricted, known-shape expression from a semi-trusted source?" β€” decides whether vm alone is actually sufficient.
  • "Does the use case need to bound execution time/resource usage, not just variable scope?" β€” vm alone does not provide that.

Code / implementation expected: Yes β€” the real, verified two-way isolation (a real global variable invisible inside the sandbox, and vice versa) is the concrete, convincing demonstration of what vm actually provides, paired honestly with what it does not.

  • vm
  • security
  • v8

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 9 sections

Read the code

JavaScriptvm's genuine, verified two-way global-scope isolation β€” neither side leaks into the other
const vm = require("vm");

global.outerVar = "set in the real global scope";
const sandbox = { sandboxVar: "set inside the sandbox" };
vm.createContext(sandbox);

console.log(vm.runInContext("typeof outerVar", sandbox));
// undefined -- the sandbox cannot see the real global's variable

vm.runInContext("var leakedFromSandbox = 42;", sandbox);
console.log(typeof global.leakedFromSandbox); // undefined -- did NOT leak out
console.log(sandbox.leakedFromSandbox);        // 42       -- landed on the sandbox instead

try {
  vm.runInContext('throw new Error("boom from sandbox")', sandbox);
} catch (e) {
  console.log(e.message); // boom from sandbox -- propagates out normally
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 140 of 152 in Node.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Node.js questions
Up nextHard

What is the package.json "exports" field and conditional exports?

Continue