Назад к обновлениям
New releaseAug 15, 2026

vm2 v3.11.6

Изолированная JavaScript-песочница для Node.js, которая выполняет недоверенный код с ограниченным доступом к встроенным модулям и ресурсам хоста посредством перехвата на основе Proxy.

Поделиться

vm2 [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![License][license-image]][license-url] Node.js CI [![Known Vulnerabilities][snyk-image]][snyk-url]

vm2 — это песочница, которая может запускать недоверенный код с использованием встроенных модулей Node из белого списка.

Важное предупреждение о безопасности

Прежде чем использовать vm2, вы должны понимать, как он работает и каковы его ограничения.

vm2 пытается изолировать недоверенный JavaScript-код в том же процессе Node.js, что и ваше приложение. Это достигается за счёт сложной сети прокси, которые перехватывают и опосредуют каждое взаимодействие между песочницей и средой хоста.

Фундаментальная проблема

JavaScript — чрезвычайно динамичный язык. Доступ к объектам можно получить через цепочки прототипов, до конструкторов можно добраться через объекты ошибок, символы предоставляют перехватчики протоколов, а асинхронное выполнение создаёт временные окна. Огромное количество способов перехода от одного объекта к другому в JavaScript делает создание абсолютно надёжной внутрипроцессной песочницы чрезвычайно сложной задачей.

Мы честно признаём эту реальность: Несмотря на все наши усилия, исследователи и специалисты по безопасности постоянно находят новые способы обхода песочницы vm2. Мы активно исправляем эти уязвимости по мере их поступления, но природа внутрипроцессной изоляции в стиле «кошки-мышки» означает, что:

  1. В будущем, скорее всего, будут обнаружены новые обходные пути. Ознакомьтесь с нашими уведомлениями о безопасности — там перечислены известные уязвимости.
  2. Вы должны поддерживать vm2 в актуальном состоянии, чтобы получать последние исправления безопасности. Подпишитесь на уведомления о безопасности и своевременно обновляйте версию.
  3. vm2 не должен быть вашей единственной линией обороны. При работе с недоверенным кодом крайне важна многоуровневая защита.

Более надёжные альтернативы

Если вам нужны более строгие гарантии изоляции, рассмотрите следующие альтернативы, обеспечивающие изоляцию на уровне процесса или оборудования:

РешениеПодходПроизводительностьКомпромиссы
isolated-vmОтдельные изоляты V8 (отдельная куча V8)БыстроВ режиме сопровождения; требует ручного обновления V8
Отдельный процесс / WorkerПотоки child_process или Worker с ограниченными правамиСредняяБолее высокие накладные расходы на IPC; данные должны быть сериализованы
Контейнеры / ВМDocker, gVisor, FirecrackerМедленноНакладные расходы на запуск; ресурсоёмко
Управляемые сервисыОблачное выполнение кода (например, AWS Lambda, Cloudflare Workers)ПеременнаяСетевая задержка; внешняя зависимость

Когда vm2 всё ещё может быть уместен

vm2 может быть уместен, когда:

  • Вам нужна тесная интеграция с объектами хоста и быстрое синхронное взаимодействие
  • Недоверенный код поступает из относительно доверенного источника (например, внутренние инструменты, плагинные системы с проверенными авторами)
  • Вы комбинируете vm2 с другими уровнями безопасности (сетевая изоляция, ограничения файловой системы, лимиты ресурсов)
  • Вы принимаете риск и активно следите за обновлениями безопасности

Если вы выполняете код из полностью недоверенных источников (например, произвольные пользовательские материалы), мы настоятельно рекомендуем использовать решение с более строгими гарантиями изоляции.

Возможности

  • Безопасно выполняет недоверенный код в одном процессе, рядом с вашим кодом
  • Полный контроль над выводом консоли песочницы
  • Песочница имеет ограниченный доступ к методам процесса
  • Из песочницы можно подключать модули (встроенные и внешние) через require
  • Можно ограничить доступ к определённым (или всем) встроенным модулям
  • Можно безопасно вызывать методы и обмениваться данными и колбэками между песочницами
  • Активно поддерживается, включает исправления для известных методов обхода (см. Предупреждение о безопасности)
  • Поддержка транспиляторов

Как это работает

  • Для создания безопасного контекста используется внутренний модуль VM.
  • Используются прокси для предотвращения выхода за пределы песочницы.
  • Переопределяется встроенный require для контроля доступа к модулям.

Для подробного знакомства с внутренним устройством vm2 см. файл CONTRIBUTING.md.

В чём разница между vm из Node и vm2?

Попробуйте сами:```js import { runInNewContext } from "node:vm";

runInNewContext('this.constructor.constructor("return process")().exit()'); console.log('Never gets executed.');

Перевод невозможен: в запросе отсутствует исходный текст (поле INPUT пустое).```js
import { VM } from 'vm2';

new VM().run('this.constructor.constructor("return process")().exit()');
// Throws ReferenceError: process is not defined

Установка```sh

npm install vm2

## Быстрые примеры```js
import { VM } from 'vm2';

const vm = new VM();
vm.run(`process.exit()`); // TypeError: process.exit is not a function

Your message contains no source text to translate.

If this is an error, please resend the chunk with the actual Markdown content. The empty input produces an empty output, which would break the concatenation sequence.```js import { NodeVM } from 'vm2';

const vm = new NodeVM({ require: { external: true, root: './', }, });

vm.run( var request = require('request'); request('http://www.google.com', function (error, response, body) { console.error(error); if (!error && response.statusCode == 200) { console.log(body); // Show the HTML for the Google homepage. } });, 'vm.js', );

## Документация

-   [VM](#vm)
-   [NodeVM](#nodevm)
-   [VMScript](#vmscript)
-   [Обработка ошибок](#error-handling)
-   [Отладка кода в песочнице](#debugging-a-sandboxed-code)
-   [Объекты только для чтения](#read-only-objects-experimental)
-   [Защищённые объекты](#protected-objects-experimental)
-   [Взаимодействие между песочницами](#cross-sandbox-relationships)
-   [CLI](#cli)
-   [Изменения с 2.x на 3.x](https://github.com/patriksimek/vm2/wiki/2.x-to-3.x-changes)
-   [Документация 1.x и 2.x](https://github.com/patriksimek/vm2/wiki/1.x-and-2.x-docs)
-   [Участие в разработке](https://github.com/patriksimek/vm2/wiki/Contributing)

## VM

VM — это простая песочница для синхронного выполнения недоверенного кода без поддержки `require`. Доступны только встроенные объекты JavaScript и `Buffer` из Node. Функции планирования (`setInterval`, `setTimeout` и `setImmediate`) по умолчанию недоступны.

**Опции:**

-   `timeout` — тайм-аут скрипта в миллисекундах. **ПРЕДУПРЕЖДЕНИЕ**: возможно, стоит использовать этот параметр вместе с `allowAsync=false`. Кроме того, работа с объектами, возвращёнными из песочницы, может выполнять произвольный код и обходить тайм-аут. Следует проверять с помощью `typeof`, является ли возвращённый объект примитивом; если нет — полностью отбрасывать его (ведение журнала или создание сообщений об ошибках с таким объектом также может снова выполнить произвольный код).
-   `sandbox` — глобальный объект VM.
-   `compiler` — `javascript` (по умолчанию), `typescript`, `coffeescript` или пользовательская функция компилятора. Если задано значение `typescript` или `coffeescript`, библиотека ожидает, что соответствующий компилятор уже установлен.
-   `eval` — если установлено значение `false`, любые вызовы `eval` или конструкторов функций (`Function`, `GeneratorFunction` и т. д.) будут выбрасывать `EvalError` (по умолчанию: `true`).
-   `wasm` — если установлено значение `false`, любая попытка скомпилировать модуль WebAssembly будет выбрасывать `WebAssembly.CompileError` (по умолчанию: `true`). Примечание: `WebAssembly.JSTag` удалён внутри песочницы по соображениям безопасности, поэтому код wasm не может перехватывать исключения JavaScript.
-   `allowAsync` — если установлено значение `false`, любая попытка запустить код с использованием `async` будет выбрасывать `VMError` (по умолчанию: `true`).
-   `bufferAllocLimit` — максимальный размер в байтах для одного запроса `Buffer.alloc` / `Buffer.allocUnsafe` / `Buffer.allocUnsafeSlow` / `Buffer(N)` / `new Buffer(N)` изнутри песочницы. Запросы, превышающие этот предел, синхронно выбрасывают `RangeError` без выполнения выделения памяти на хосте. По умолчанию: `Infinity` (без ограничения, полностью обратно совместимо). Приложениям, встраивающим vm2 и запускающим недоверенный код в средах с ограниченной памятью (Docker / Kubernetes / Lambda / serverless), следует выбирать конечный предел (например, `32 * 1024 * 1024`) как часть многоуровневой защиты от DoS, так же как они выбирают `timeout`. См. [Рекомендации по усилению защиты](#hardening-recommendations) ниже.

**ВАЖНО**: Тайм-аут действует только на синхронный код, который вы запускаете через `run`. Тайм-аут **НЕ** действует ни на один метод, возвращённый VM. Существуют ситуации, когда тайм-аут не работает — см. [#244](https://github.com/patriksimek/vm2/pull/244).```js
import { VM } from 'vm2';

const vm = new VM({
	timeout: 1000,
	allowAsync: false,
	sandbox: {},
});

vm.run('process.exit()'); // throws ReferenceError: process is not defined

Вы также можете извлекать значения из VM.```js let number = vm.run('1337'); // returns 1337

**СОВЕТ**: Смотрите тесты для дополнительных примеров использования.

## NodeVM

В отличие от `VM`, `NodeVM` позволяет подключать модули так же, как в обычном контексте Node.

**Опции:**

-   `console` - `inherit` для включения консоли, `redirect` для перенаправления в события, `off` для отключения консоли (по умолчанию: `inherit`).
-   `sandbox` - глобальный объект VM.
-   `compiler` - `javascript` (по умолчанию), `typescript`, `coffeescript` или пользовательская функция компилятора (которая получает код и его путь к файлу). Библиотека ожидает, что у вас предустановлен компилятор, если значение установлено в `typescript` или `coffeescript`.
-   `eval` - Если установлено значение `false`, любые вызовы `eval` или конструкторов функций (`Function`, `GeneratorFunction` и т.д.) будут вызывать `EvalError` (по умолчанию: `true`).
-   `wasm` - Если установлено значение `false`, любая попытка компиляции модуля WebAssembly вызовет `WebAssembly.CompileError` (по умолчанию: `true`). Примечание: `WebAssembly.JSTag` удаляется внутри песочницы по соображениям безопасности, поэтому код wasm не может перехватывать исключения JavaScript.
-   `bufferAllocLimit` - Та же семантика, что и в `VM` — максимальный размер в байтах для одного запроса семейства `Buffer.alloc` изнутри песочницы. По умолчанию: `Infinity`. См. [Рекомендации по укреплению](#hardening-recommendations).
-   `sourceExtensions` - Массив расширений файлов, которые следует рассматривать как исходный код (по умолчанию: `['js']`).
-   `require` - `true`, объект или Resolver для включения метода `require` (по умолчанию: `false`).
-   `require.external` - Значения могут быть `true`, массивом разрешённых внешних модулей или объектом (по умолчанию: `false`). Все пути, соответствующие `/node_modules/${any_allowed_external_module}/(?!/node_modules/)`, разрешены для подключения.
-   `require.external.modules` - Массив разрешённых внешних модулей. Также поддерживает подстановочные знаки, поэтому указание, например, `['@scope/*-ver-??]` разрешит использование всех модулей с именем вида `@scope/something-ver-aa`, `@scope/other-ver-11` и т.д. Подстановочный знак `*` не соответствует разделителям путей.
-   `require.external.transitive` - Логическое значение, указывающее, разрешены ли транзитивные зависимости внешних модулей (по умолчанию: `false`). **ПРЕДУПРЕЖДЕНИЕ**: Если модуль подключается транзитивно, любой модуль затем может подключить его обычным образом, даже если это было невозможно до его загрузки.
-   `require.builtin` - Массив разрешённых встроенных модулей, принимает ["\*"] для всех (по умолчанию: нет). **ПРЕДУПРЕЖДЕНИЕ**: "\*" может быть опасен, так как могут быть добавлены новые встроенные модули.
-   `require.root` - Ограниченный путь(и), откуда можно подключать локальные модули (по умолчанию: любой путь).
-   `require.mock` - Коллекция mock-модулей (как внешних, так и встроенных).
-   `require.context` - `host` (по умолчанию) для подключения модулей в хосте и проксирования их в песочницу. `sandbox` для загрузки, компиляции и подключения модулей в песочнице. `callback(moduleFilename, ext)` для динамического выбора контекста для каждого модуля. Если ничего не указано, по умолчанию используется sandbox. За исключением `events`, встроенные модули всегда подключаются в хосте и проксируются в песочницу.
-   `require.import` - Массив модулей для загрузки в NodeVM при запуске.
-   `require.resolve` - Дополнительная функция поиска на случай, если модуль не был найден в одном из стандартных путей поиска node.
-   `require.customRequire` - Используется вместо функции `require` для загрузки модулей из хоста.
-   `require.strict` - `false`, чтобы не принуждать к строгому режиму модули, загружаемые через require (по умолчанию: `true`).
-   `require.fs` - Пользовательская реализация файловой системы.
-   `nesting` - **ПРЕДУПРЕЖДЕНИЕ**: Разрешение этого является риском для безопасности, поскольку скрипты могут создать NodeVM, который сможет подключать любой модуль хоста. `true` для включения вложенности VM (по умолчанию: `false`).
-   `wrapper` - `commonjs` (по умолчанию) для обёртки скрипта в CommonJS-обёртку, `none` для получения значения, возвращаемого скриптом.
-   `argv` - Массив для передачи в `process.argv`.
-   `env` - Объект для передачи в `process.env`.
-   `strict` - `true` для перевода загруженных модулей в строгий режим (по умолчанию: `false`).

**ВАЖНО**: Тайм-аут не действует для NodeVM, поэтому он не защищён от `while (true) {}` или подобного зла.

**ПОМНИТЕ**: Чем больше модулей вы разрешаете, тем более хрупкой становится ваша песочница.```js
import { NodeVM } from 'vm2';

const vm = new NodeVM({
	console: 'inherit',
	sandbox: {},
	require: {
		external: true,
		builtin: ['fs', 'path'],
		root: './',
		mock: {
			fs: {
				readFileSync: () => 'Nice try!',
			},
		},
	},
});

// Sync

let functionInSandbox = vm.run('module.exports = function(who) { console.log("hello "+ who); }');
functionInSandbox('world');

// Async

let functionWithCallbackInSandbox = vm.run('module.exports = function(who, callback) { callback("hello "+ who); }');
functionWithCallbackInSandbox('world', greeting => {
	console.log(greeting);
});

Когда wrapper установлен в none, NodeVM ведёт себя больше как VM для синхронного кода.```js assert.ok(vm.run('return true') === true);

**СОВЕТ**: Дополнительные примеры использования см. в тестах.

### Загрузка модулей по относительному пути

Чтобы загружать модули по относительному пути, вы должны передать полный путь выполняемого скрипта в качестве второго аргумента методу `run` модуля `vm`, если скрипт является строкой. Имя файла затем отображается в любых трассировках стека, генерируемых скриптом.```js
vm.run('require("foobar")', '/data/myvmscript.js');

Если запускаемый вами скрипт является VMScript, путь указывается в конструкторе VMScript.```js const script = new VMScript('require("foobar")', { filename: '/data/myvmscript.js' }); vm.run(script);

### Резолвер

Резолвер может быть создан через `makeResolverFromLegacyOptions` и использоваться для нескольких экземпляров `NodeVM`, что позволяет совместно использовать скомпилированный код модулей, потенциально ускоряя время загрузки. Первый пример `NodeVM` может быть переписан с использованием `makeResolverFromLegacyOptions` следующим образом.```js
const resolver = makeResolverFromLegacyOptions({
	external: true,
	builtin: ['fs', 'path'],
	root: './',
	mock: {
		fs: {
			readFileSync: () => 'Nice try!',
		},
	},
});
const vm = new NodeVM({
	console: 'inherit',
	sandbox: {},
	require: resolver,
});

VMScript

Вы можете повысить производительность, используя предварительно скомпилированные скрипты. Предварительно скомпилированный VMScript можно запускать несколько раз. Важно отметить, что код не привязан к какой-либо VM (контексту); скорее, он привязывается перед каждым запуском, только для этого запуска.```js import { VM, VMScript } from 'vm2';

const vm = new VM(); const script = new VMScript('Math.random()'); console.log(vm.run(script)); console.log(vm.run(script));

Оно работает как для `VM`, так и для `NodeVM`.```js
import { NodeVM, VMScript } from 'vm2';

const vm = new NodeVM();
const script = new VMScript('module.exports = Math.random()');
console.log(vm.run(script));
console.log(vm.run(script));

Код компилируется автоматически при первом запуске. Код можно скомпилировать в любой момент с помощью script.compile(). После компиляции кода этот метод не оказывает никакого эффекта.

Обработка ошибок

Ошибки при компиляции кода и синхронном выполнении кода можно обрабатывать с помощью try-catch. Ошибки при асинхронном выполнении кода можно обрабатывать, подключив обработчик события uncaughtException к process в Node.```js try { var script = new VMScript('Math.random()').compile(); } catch (err) { console.error('Failed to compile script.', err); }

try { vm.run(script); } catch (err) { console.error('Failed to execute script.', err); }

process.on('uncaughtException', err => { console.error('Asynchronous error caught.', err); });

## Отладка кода в песочнице

Вы можете отлаживать или проверять код, работающий в песочнице, так же, как если бы он выполнялся в обычном процессе.

-   Вы можете использовать точки останова (для этого необходимо указать имя файла сценария).
-   Вы можете использовать ключевое слово `debugger`.
-   Вы можете использовать step-in, чтобы войти внутрь кода, выполняемого в песочнице.

### Пример

/tmp/main.js:```js
import { VM, VMScript } from 'vm2';
import { readFileSync } from 'node:fs';

const file = `${__dirname}/sandbox.js`;

// By providing a file name as second argument you enable breakpoints
const script = new VMScript(readFileSync(file), file);

new VM().run(script);

/tmp/sandbox.js```js const foo = 'ahoj';

// The debugger keyword works just fine everywhere. // Even without specifying a file name to the VMScript object. debugger;

## Read-only objects (экспериментально)

Чтобы предотвратить добавление, изменение или удаление свойств проксированных объектов из песочницы, можно использовать методы `freeze`, чтобы сделать объект доступным только для чтения. Это работает только внутри VM. Замороженные объекты изменяются глубоко. Примитивные типы заморозить нельзя.

**Пример без использования `freeze`:**```js
const util = {
	add: (a, b) => a + b,
};

const vm = new VM({
	sandbox: { util },
});

vm.run('util.add = (a, b) => a - b');
console.log(util.add(1, 1)); // returns 0

Пример использования freeze:```js const vm = new VM(); // Objects specified in the sandbox cannot be frozen. vm.freeze(util, 'util'); // Second argument adds object to global.

vm.run('util.add = (a, b) => a - b'); // Fails silently when not in strict mode. console.log(util.add(1, 1)); // returns 2

**ВАЖНО:** Невозможно заморозить объекты, которые уже были проксированы в VM.

## Защищённые объекты (экспериментально)

В отличие от `freeze`, этот метод позволяет скриптам в песочнице добавлять, изменять или удалять свойства объектов, за одним исключением — невозможно прикреплять функции. Поэтому скрипты в песочнице не могут изменять такие методы, как `toJSON`, `toString` или `inspect`.

**ВАЖНО:** Невозможно защитить объекты, которые уже были проксированы в VM.

## Взаимосвязи между песочницами```js
const assert = require('assert');
const { VM } = require('vm2');

const sandbox = {
	object: new Object(),
	func: new Function(),
	buffer: new Buffer([0x01, 0x05]),
};

const vm = new VM({ sandbox });

assert.ok(vm.run(`object`) === sandbox.object);
assert.ok(vm.run(`object instanceof Object`));
assert.ok(vm.run(`object`) instanceof Object);
assert.ok(vm.run(`object.__proto__ === Object.prototype`));
assert.ok(vm.run(`object`).__proto__ === Object.prototype);

assert.ok(vm.run(`func`) === sandbox.func);
assert.ok(vm.run(`func instanceof Function`));
assert.ok(vm.run(`func`) instanceof Function);
assert.ok(vm.run(`func.__proto__ === Function.prototype`));
assert.ok(vm.run(`func`).__proto__ === Function.prototype);

assert.ok(vm.run(`new func() instanceof func`));
assert.ok(vm.run(`new func()`) instanceof sandbox.func);
assert.ok(vm.run(`new func().__proto__ === func.prototype`));
assert.ok(vm.run(`new func()`).__proto__ === sandbox.func.prototype);

assert.ok(vm.run(`buffer`) === sandbox.buffer);
assert.ok(vm.run(`buffer instanceof Buffer`));
assert.ok(vm.run(`buffer`) instanceof Buffer);
assert.ok(vm.run(`buffer.__proto__ === Buffer.prototype`));
assert.ok(vm.run(`buffer`).__proto__ === Buffer.prototype);
assert.ok(vm.run(`buffer.slice(0, 1) instanceof Buffer`));
assert.ok(vm.run(`buffer.slice(0, 1)`) instanceof Buffer);

CLI

Прежде чем использовать vm2 в командной строке, установите его глобально с помощью npm install vm2 -g.```sh vm2 ./script.js

## Рекомендации по усилению безопасности

vm2 предотвращает побег из песочницы (получение недоверенным кодом доступа к окружению хоста). Сам по себе он **не** предотвращает все формы исчерпания ресурсов или отказа в обслуживании. Разработчикам, запускающим недоверенный код, следует добавить следующие многоуровневые защиты вокруг песочницы.

### 1. Ограничьте выделение памяти с помощью `bufferAllocLimit`

Один вызов `Buffer.alloc(N)` с управляемым атакующим `N` выполняется как одно синхронное C++-выделение памяти на хосте, которое `timeout` V8 не может прервать. В средах с ограниченной памятью полезная нагрузка песочницы размером ~100 байт может вызвать скачок RSS хоста на 100 МБ+ и привести к сбою процесса хоста из-за OOM. Установите `bufferAllocLimit` (например, `32 * 1024 * 1024`), чтобы ограничить отдельные выделения:```js
const vm = new VM({
	timeout: 1000,
	bufferAllocLimit: 32 * 1024 * 1024,
	allowAsync: false,
});

Ограничение также применяется к устаревшим путям Buffer(N) и new Buffer(N). Обратите внимание, что совокупное исчерпание (множество мелких выделений, Buffer.concat, Uint8Array, String.repeat, Array(n).fill() и т.д.) не покрывается этим ограничением — для полного покрытия комбинируйте его с лимитом памяти на стороне хоста (--max-old-space-size, лимит контейнера, cgroup).

2. Установите обработчик unhandledRejection на стороне хоста

Существует класс DoS-атак с прерыванием хост-процесса, когда код песочницы создаёт async function, async function* или await using, тело которого выбрасывает значение, вызывающее ошибку в окружении хоста при форматировании стека (например, e.name = Symbol(); e.stack). V8 создаёт промис отклонения через внутренний Promise окружения, что обходит обёртку подкласса Promise в vm2, поэтому отклонение уходит на хост как unhandledRejection. На Node 15+ поведение по умолчанию — завершение процесса.

Закрытие этой уязвимости требует изменения наблюдаемого поведения хоста, поэтому vm2 не поставляет исправление по умолчанию. Встраивающие приложения должны установить обработчик на уровне процесса, который перехватывает (или логирует) отклонения, исходящие из песочницы:```js // Recommended: filter rejections that originated inside vm2 and swallow them, // while letting your own host-side rejections propagate. process.on('unhandledRejection', (reason, promise) => { // Heuristic: rejections from the sandbox frequently surface as values // without proper Error semantics, or with stacks pointing at vm.js. // Adjust the predicate to match your application. if (looksLikeSandboxOrigin(reason)) { return; // swallow — don't terminate the process } // Otherwise: handle (or rethrow) as normal for your host code. yourLogger.error('unhandled rejection', reason); });

Если в вашем приложении нет других источников необработанных отклонений, допустимо глобальное проглатывание + журналирование:```js
process.on('unhandledRejection', reason => {
	yourLogger.warn('swallowed sandbox rejection', reason);
});

A scoped fix may ship behind an opt-in swallowSandboxUnhandledRejections flag in a future minor release; until then, the host-side handler is the recommended mitigation.

3. Run with a process-level memory cap

Even with bufferAllocLimit set, run the host process with --max-old-space-size (or an equivalent container memory limit) sized for the workload. The cap protects against the single-allocation primitive; the OS-level limit protects against aggregate exhaustion and against any future allocation primitive vm2 hasn't yet capped.

4. Treat require.builtin: ['*'] as a non-sandbox configuration

The '*' wildcard expands to most Node built-ins, including child_process, fs, dgram, net, http, and dns. These are full host-capability primitives — require('child_process').execSync('id') is reachable from the sandbox under '*'. vm2's '*' semantics are intentional (some embedders run trusted-but-isolated code), but it should not be used as a default for untrusted code. Prefer an explicit allowlist of the smallest set of modules your sandbox actually needs.

5. nesting: true is an escape hatch

nesting: true lets sandbox code require('vm2') and construct nested NodeVMs. The nested VM's require config is chosen by the sandbox code that constructs it, not constrained by the outer VM. Concretely:```js const vm = new NodeVM({ nesting: true, require: { builtin: [] } }); vm.run( const { NodeVM: NVM } = require('vm2'); // Inner VM's config is whatever the sandbox writes here: const inner = new NVM({ require: { builtin: ['child_process'] } }); inner.run('require("child_process").execSync("id")'); // RCE);

Если вы установите `nesting: true`, вы фактически предоставляете песочнице тот же уровень доверия, что и у вас. **Не включайте `nesting: true` для недоверенного кода.** Используйте его только тогда, когда вы доверяете самому изолированному коду, но хотите получить семантику выполнения в стиле VM (свежий глобальный объект, контролируемые тайм-ауты) по причинам, не связанным с безопасностью.

`nesting: true` **требует явного объекта конфигурации `require`** (например, `require: { builtin: [] }` или `require: {}`). Любая другая форма — `require: false`, `require: undefined`, `require: null` или полное отсутствие `require` — вызывает `VMError` при создании (GHSA-m4wx-m65x-ghrr, заменяет GHSA-8hg8-63c5-gwmx). Все эти формы создают резолвер только с NESTING_OVERRIDE: песочница может выполнить `require('vm2')`, но ничего больше, что является чистым примитивом побега без легитимного применения. Чтобы запретить все require, удалите `nesting: true`. Чтобы разрешить вложенные VM, укажите явную конфигурацию `require`, чтобы компромисс был виден в месте вызова.

## Известные проблемы

-   Невозможно определить класс, который расширяет проксированный класс. Это включает использование проксированного класса в `Object.create`.
-   Прямой eval не работает.
-   При логировании массивов песочницы часть массива повторяется в свойствах.
-   Преобразования исходного кода могут привести к другой строке исходного кода для функции.
-   Существуют способы вызвать сбой процесса node изнутри песочницы. См. [Рекомендации по усилению защиты](#hardening-recommendations).

[npm-image]: https://img.shields.io/npm/v/vm2.svg
[npm-url]: https://www.npmjs.com/package/vm2
[license-image]: https://img.shields.io/npm/l/vm2.svg
[license-url]: https://raw.githubusercontent.com/patriksimek/vm2/resurrection/LICENSE.md
[downloads-image]: https://img.shields.io/npm/dm/vm2.svg
[downloads-url]: https://www.npmjs.com/package/vm2
[snyk-image]: https://snyk.io/test/github/patriksimek/vm2/badge.svg
[snyk-url]: https://snyk.io/test/github/patriksimek/vm2

Категории