Zurück zu den Updates
New releaseAug 15, 2026

vm2 v3.11.6

Isolierte JavaScript-Sandbox für Node.js, die nicht vertrauenswürdigen Code mit eingeschränktem Zugriff auf eingebaute Module und Host-Ressourcen über Proxy-basierte Abfangmechanismen ausführt.

Teilen

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 ist eine Sandbox, die nicht vertrauenswürdigen Code mit auf der Whitelist stehenden eingebauten Node-Modulen ausführen kann.

Wichtiger Sicherheitshinweis

Bevor Sie vm2 verwenden, sollten Sie verstehen, wie es funktioniert und wo seine Grenzen liegen.

vm2 versucht, nicht vertrauenswürdigen JavaScript-Code im selben Node.js-Prozess wie Ihre Anwendung in einer Sandbox auszuführen. Dies geschieht über ein komplexes Netzwerk aus Proxies, die jede Interaktion zwischen der Sandbox und der Host-Umgebung abfangen und vermitteln.

Die grundlegende Herausforderung

JavaScript ist eine außergewöhnlich dynamische Sprache. Auf Objekte kann über Prototyp-Ketten zugegriffen werden, Konstruktoren sind über Fehlerobjekte erreichbar, Symbole bieten Protokoll-Hooks, und asynchrone Ausführung erzeugt Timing-Fenster. Die schiere Anzahl an Möglichkeiten, in JavaScript von einem Objekt zu einem anderen zu gelangen, macht es äußerst schwierig, eine luftdichte In-Process-Sandbox zu bauen.

Wir sind ehrlich, was diese Realität betrifft: Trotz aller Bemühungen entdecken Forscher und Sicherheitsexperten kontinuierlich neue Wege, aus der vm2-Sandbox auszubrechen. Wir patchen diese Schwachstellen aktiv, sobald sie gemeldet werden, aber die Natur des Katz-und-Maus-Spiels beim In-Process-Sandboxing bedeutet, dass:

  1. In Zukunft werden wahrscheinlich neue Bypasses entdeckt. Überprüfen Sie unsere Sicherheitshinweise auf bekannte Schwachstellen.
  2. Sie müssen vm2 aktualisiert halten, um von den neuesten Sicherheitskorrekturen zu profitieren. Abonnieren Sie die Sicherheitshinweise und aktualisieren Sie umgehend.
  3. vm2 sollte nicht Ihre einzige Verteidigungslinie sein. Mehrschichtige Verteidigung ist beim Ausführen von nicht vertrauenswürdigem Code unerlässlich.

Robustere Alternativen

Wenn Sie stärkere Isolationsgarantien benötigen, ziehen Sie diese Alternativen in Betracht, die echte Prozess- oder Hardware-Isolation bieten:

LösungAnsatzLeistungKompromisse
isolated-vmSeparate V8-Isolate (getrennter V8-Heap)SchnellIm Wartungsmodus; erfordert manuelle V8-Updates
Separater Prozess / Workerchild_process oder Worker-Threads mit eingeschränkten BerechtigungenMittelHöherer IPC-Overhead; Daten müssen serialisiert werden
Container / VMsDocker, gVisor, FirecrackerLangsamStart-Overhead; ressourcenintensiv
Verwaltete DiensteCloudbasierte Codeausführung (z. B. AWS Lambda, Cloudflare Workers)VariabelNetzwerklatenz; externe Abhängigkeit

Wann vm2 weiterhin geeignet sein kann

vm2 kann geeignet sein, wenn:

  • Sie eine enge Integration mit Host-Objekten und eine schnelle synchrone Kommunikation benötigen
  • Der nicht vertrauenswürdige Code aus einer relativ vertrauenswürdigen Quelle stammt (z. B. interne Tools, Plugin-Systeme mit geprüften Autoren)
  • Sie vm2 mit anderen Sicherheitsebenen kombinieren (Netzwerkisolation, Dateisystemeinschränkungen, Ressourcenlimits)
  • Sie das Risiko akzeptieren und aktiv Sicherheitsupdates überwachen

Wenn Sie Code aus völlig nicht vertrauenswürdigen Quellen ausführen (z. B. beliebige Benutzereinsendungen), empfehlen wir nachdrücklich, eine Lösung mit stärkeren Isolationsgarantien zu verwenden.

Funktionen

  • Führt nicht vertrauenswürdigen Code sicher in einem einzigen Prozess neben Ihrem Code aus
  • Volle Kontrolle über die Konsolenausgabe der Sandbox
  • Die Sandbox hat eingeschränkten Zugriff auf die Methoden des Prozesses
  • Es ist möglich, Module (eingebaute und externe) aus der Sandbox zu laden
  • Sie können den Zugriff auf bestimmte (oder alle) eingebauten Module einschränken
  • Sie können sicher Methoden aufrufen und Daten und Callbacks zwischen Sandboxen austauschen
  • Aktiv gepflegt mit Patches für bekannte Ausbruchsmethoden (siehe Sicherheitshinweis)
  • Transpiler-Unterstützung

Wie es funktioniert

  • Es verwendet das interne VM-Modul, um einen sicheren Kontext zu erstellen.
  • Es verwendet Proxies, um das Entkommen aus der Sandbox zu verhindern.
  • Es überschreibt das eingebaute require, um den Zugriff auf Module zu kontrollieren.

Für einen detaillierten Blick in die Interna von vm2 siehe die Datei CONTRIBUTING.md.

Was ist der Unterschied zwischen dem vm von Node und vm2?

Probieren Sie es selbst aus:```js import { runInNewContext } from "node:vm";

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

Dadurch können Benutzer Berechtigungen miteinander teilen und gleichzeitig separate Notizen haben, ohne sich gegenseitig zu stören.

#### Häufige Filter

Dieser Abschnitt enthält häufig verwendete Sicherheitsfilter für [[security-filters]].

- [[antivirus-login-ips|AntiVirus-Anmelde-IPs]] (2,2k Upvotes)
- [[c2-ip-filter-list|C2-IP-Filterliste]] (2,2k Upvotes)
- [[GoogleBot IPs]]
- [[darklist]]
- [[abuse-ch]]
- [[feodo-tracker]]
- [[malsilo]]
- [[urlhaus]]
- [[alienvault-otx]]
- [[digital-side]]```js
import { VM } from 'vm2';

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

Installation```sh

npm install vm2

## Schnelle Beispiele```js
import { VM } from 'vm2';

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

[!WARNING]
Dieses Exploit könnte die Systemstabilität beeinträchtigen und möglicherweise Datenverlust verursachen. Verwenden Sie es nur auf Systemen, die Sie besitzen oder für die Sie die ausdrückliche Erlaubnis zum Testen haben!

Hauptfunktionen 🎯

  • Plattformübergreifender C2-Server — GUI-basierte Befehls- und Kontrollschnittstelle mit Echtzeit-Sitzungsverwaltung.
  • Erweiterte Kommunikationskanäle — Domain Fronting, DNS-Tunneling und benutzerdefinierte Dead Drop Resolver.
  • Payload-Erstellung — Erstellen von Ausgaben in verschiedenen Formaten, einschließlich ausführbarer Dateien, PowerShell, HTA und VBA.
  • Tarnkappenfunktionen — AMSI-Umgehung, Code-Verschleierung, zufällige Beacon-Intervalle und anpassbare C2-Profile.
  • Modulare Architektur — Funktionalität durch Plugin-System und Skripting erweiterbar.
  • Post-Exploitation-Werkzeuge — Keylogging, Screenshot-Aufnahme, Dateisystem-Interaktion und Rechteausweitung.
  • Netzwerkoperationen — SOCKS5-Proxy, Port-Scanning, laterale Bewegung und Pivot-Fähigkeiten.
  • Tarnfunktionen — Prozessinjektion, speicherresidente Payloads und verschlüsselte Kommunikation.

Kernfunktionalität ⚙️

  • ssl — Verschlüsselt den gesamten bösartigen Netzwerkverkehr mit TLS
  • proxy — Anonymes Routing über TOR-Netzwerk-.onion-Adressen
  • dnscrypt — Schützt DNS-Tunneling mit Public-Key-Kryptografie
  • aes-256-cbc — Hochsichere Verschlüsselung für .poison-Dateien (Payload/Konfiguration)
  • gzip — Reduziert Datenübertragungen durch Komprimierung des Netzwerkverkehrs
  • domainfronting — Versteckt C2 hinter CDNs wie Cloudflare und Google
  • cookies/session — Entführt legitime Benutzerauthentifizierungstoken
  • cookies/session/stealer — Extrahiert und missbraucht gespeicherte Anmeldeinformationen
  • certcheck — Identifiziert abgefangenen Verkehr durch Zertifikatsanalyse
  • evade — Umgeht heuristische Erkennung durch verhaltensbasierte AV/EDR```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', );

## Dokumentation

-   [VM](#vm)
-   [NodeVM](#nodevm)
-   [VMScript](#vmscript)
-   [Fehlerbehandlung](#error-handling)
-   [Debuggen von Sandbox-Code](#debugging-a-sandboxed-code)
-   [Schreibgeschützte Objekte](#read-only-objects-experimental)
-   [Geschützte Objekte](#protected-objects-experimental)
-   [Beziehungen zwischen Sandboxes](#cross-sandbox-relationships)
-   [CLI](#cli)
-   [Änderungen von 2.x zu 3.x](https://github.com/patriksimek/vm2/wiki/2.x-to-3.x-changes)
-   [Dokumentation zu 1.x und 2.x](https://github.com/patriksimek/vm2/wiki/1.x-and-2.x-docs)
-   [Mitwirken](https://github.com/patriksimek/vm2/wiki/Contributing)

## VM

VM ist eine einfache Sandbox, um nicht vertrauenswürdigen Code synchron ohne die `require`-Funktion auszuführen. Nur die in JavaScript eingebauten Objekte und Nodes `Buffer` sind verfügbar. Scheduling-Funktionen (`setInterval`, `setTimeout` und `setImmediate`) sind standardmäßig nicht verfügbar.

**Optionen:**

-   `timeout` - Skript-Timeout in Millisekunden. **WARNUNG**: Sie sollten diese Option wahrscheinlich zusammen mit `allowAsync=false` verwenden. Darüber hinaus kann die Arbeit mit von der Sandbox zurückgegebenen Objekten beliebigen Code ausführen und den Timeout umgehen. Man sollte testen, ob das zurückgegebene Objekt ein primitiver Wert ist (mit `typeof`) und es andernfalls vollständig verwerfen (auch das Protokollieren oder das Erstellen von Fehlermeldungen mit einem solchen Objekt kann erneut beliebigen Code ausführen).
-   `sandbox` - Das globale Objekt der VM.
-   `compiler` - `javascript` (Standard), `typescript`, `coffeescript` oder eine benutzerdefinierte Compiler-Funktion. Die Bibliothek erwartet, dass der Compiler bereits installiert ist, wenn der Wert auf `typescript` oder `coffeescript` gesetzt ist.
-   `eval` - Wenn auf `false` gesetzt, werfen alle Aufrufe von `eval` oder Funktionskonstruktoren (`Function`, `GeneratorFunction`, etc.) einen `EvalError` (Standard: `true`).
-   `wasm` - Wenn auf `false` gesetzt, wirft jeder Versuch, ein WebAssembly-Modul zu kompilieren, einen `WebAssembly.CompileError` (Standard: `true`). Hinweis: `WebAssembly.JSTag` wird aus Sicherheitsgründen innerhalb der Sandbox entfernt, sodass Wasm-Code keine JavaScript-Ausnahmen abfangen kann.
-   `allowAsync` - Wenn auf `false` gesetzt, wirft jeder Versuch, Code mit `async` auszuführen, einen `VMError` (Standard: `true`).
-   `bufferAllocLimit` - Maximale Größe in Bytes für eine einzelne `Buffer.alloc`- / `Buffer.allocUnsafe`- / `Buffer.allocUnsafeSlow`- / `Buffer(N)`- / `new Buffer(N)`-Anfrage aus der Sandbox heraus. Anfragen, die dieses Limit überschreiten, werfen synchron einen `RangeError`, ohne die Host-Allokation durchzuführen. Standard: `Infinity` (kein Limit, vollständig abwärtskompatibel). Einbettende Anwendungen, die nicht vertrauenswürdigen Code in speicherbegrenzten Umgebungen (Docker / Kubernetes / Lambda / Serverless) ausführen, sollten sich für ein endliches Limit (z. B. `32 * 1024 * 1024`) als Teil einer mehrschichtigen DoS-Abwehr entscheiden, genau wie sie sich für `timeout` entscheiden. Siehe [Härtungsempfehlungen](#hardening-recommendations) unten.

**WICHTIG**: Der Timeout wirkt nur auf synchronen Code, den Sie über `run` ausführen. Der Timeout funktioniert **NICHT** bei Methoden, die von der VM zurückgegeben werden. Es gibt einige Situationen, in denen der Timeout nicht funktioniert – siehe [#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

Sie können auch Werte aus der VM abrufen.```js let number = vm.run('1337'); // returns 1337

**TIPP**: Siehe Tests für weitere Verwendungsbeispiele.

## NodeVM

Im Gegensatz zu `VM` kannst du mit `NodeVM` Module auf dieselbe Weise laden wie im regulären Node-Kontext.

**Optionen:**

-   `console` - `inherit`, um die Konsole zu aktivieren, `redirect`, um auf Ereignisse umzuleiten, `off`, um die Konsole zu deaktivieren (Standard: `inherit`).
-   `sandbox` - Das globale Objekt der VM.
-   `compiler` - `javascript` (Standard), `typescript`, `coffeescript` oder eine benutzerdefinierte Compiler-Funktion (die den Code und dessen Dateipfad erhält). Die Bibliothek erwartet, dass der Compiler bereits installiert ist, wenn der Wert auf `typescript` oder `coffeescript` gesetzt wird.
-   `eval` - Wenn auf `false` gesetzt, lösen alle Aufrufe von `eval` oder Funktionskonstruktoren (`Function`, `GeneratorFunction`, usw.) einen `EvalError` aus (Standard: `true`).
-   `wasm` - Wenn auf `false` gesetzt, führt jeder Versuch, ein WebAssembly-Modul zu kompilieren, zu einem `WebAssembly.CompileError` (Standard: `true`). Hinweis: `WebAssembly.JSTag` wird aus Sicherheitsgründen in der Sandbox entfernt, sodass Wasm-Code keine JavaScript-Ausnahmen abfangen kann.
-   `bufferAllocLimit` - Gleiche Semantik wie bei `VM` — maximale Größe in Bytes für eine einzelne Anforderung der `Buffer.alloc`-Familie innerhalb der Sandbox. Standard: `Infinity`. Siehe [Härtungsempfehlungen](#hardening-recommendations).
-   `sourceExtensions` - Array von Dateierweiterungen, die als Quellcode behandelt werden sollen (Standard: `['js']`).
-   `require` - `true`, ein Objekt oder ein Resolver, um die `require`-Methode zu aktivieren (Standard: `false`).
-   `require.external` - Werte können `true`, ein Array erlaubter externer Module oder ein Objekt sein (Standard: `false`). Alle Pfade, die auf `/node_modules/${any_allowed_external_module}/(?!/node_modules/)` passen, können per `require` geladen werden.
-   `require.external.modules` - Array erlaubter externer Module. Unterstützt auch Wildcards, sodass zum Beispiel die Angabe `['@scope/*-ver-??]` die Verwendung aller Module mit einem Namen der Form `@scope/something-ver-aa`, `@scope/other-ver-11`, usw. erlaubt. Die Wildcard `*` passt nicht auf Pfadtrennzeichen.
-   `require.external.transitive` - Boolean, das angibt, ob transitive Abhängigkeiten externer Module erlaubt sind (Standard: `false`). **WARNUNG**: Wenn ein Modul transitiv geladen wird, kann jedes Modul es anschließend normal laden, auch wenn dies vor dem Laden nicht möglich war.
-   `require.builtin` - Array erlaubter eingebauter Module, akzeptiert ["\*"] für alle (Standard: keine). **WARNUNG**: "\*" kann gefährlich sein, da neue eingebaute Module hinzugefügt werden können.
-   `require.root` - Eingeschränkter Pfad bzw. eingeschränkte Pfade, in denen lokale Module geladen werden können (Standard: jeder Pfad).
-   `require.mock` - Sammlung von Mock-Modulen (sowohl extern als auch eingebaut).
-   `require.context` - `host` (Standard), um Module im Host zu laden und sie in die Sandbox zu proxen. `sandbox`, um Module in der Sandbox zu laden, zu kompilieren und per `require` zu laden. `callback(moduleFilename, ext)`, um pro Modul dynamisch einen Kontext zu wählen. Wenn nichts angegeben ist, ist der Standard `sandbox`. Mit Ausnahme von `events` werden eingebaute Module immer im Host geladen und in die Sandbox geproxt.
-   `require.import` - Ein Array von Modulen, die beim Start in die NodeVM geladen werden sollen.
-   `require.resolve` - Eine zusätzliche Suchfunktion für den Fall, dass ein Modul in einem der traditionellen Node-Suchpfade nicht gefunden wurde.
-   `require.customRequire` - Verwende dies anstelle der `require`-Funktion, um Module aus dem Host zu laden.
-   `require.strict` - `false`, um den strengen Modus bei per `require` geladenen Modulen nicht zu erzwingen (Standard: `true`).
-   `require.fs` - Benutzerdefinierte Dateisystemimplementierung.
-   `nesting` - **WARNUNG**: Dies zu erlauben ist ein Sicherheitsrisiko, da Skripte eine NodeVM erstellen können, die jedes Host-Modul laden kann. `true`, um die Verschachtelung von VMs zu aktivieren (Standard: `false`).
-   `wrapper` - `commonjs` (Standard), um das Skript in einen CommonJS-Wrapper einzuwickeln, `none`, um den vom Skript zurückgegebenen Wert abzurufen.
-   `argv` - Array, das an `process.argv` übergeben werden soll.
-   `env` - Objekt, das an `process.env` übergeben werden soll.
-   `strict` - `true`, um Module im strengen Modus zu laden (Standard: `false`).

**WICHTIG**: Timeout ist bei NodeVM nicht wirksam, daher ist es nicht immun gegen `while (true) {}` oder ähnliche bösartige Konstrukte.

**DENK DARAN**: Je mehr Module du erlaubst, desto fragiler wird deine Sandbox.```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);
});

Wenn wrapper auf none gesetzt ist, verhält sich NodeVM für synchronen Code eher wie VM.```js assert.ok(vm.run('return true') === true);

**TIPP**: Siehe Tests für weitere Verwendungsbeispiele.

### Laden von Modulen über relative Pfade

Um Module über relative Pfade zu laden, müssen Sie den vollständigen Pfad des Skripts, das Sie ausführen, als zweites Argument an die `run`-Methode von vm übergeben, wenn das Skript ein String ist. Der Dateiname wird dann in allen Stack-Traces angezeigt, die vom Skript erzeugt werden.```js
vm.run('require("foobar")', '/data/myvmscript.js');

Wenn das Skript, das Sie ausführen, ein VMScript ist, wird der Pfad im VMScript-Konstruktor angegeben.```js const script = new VMScript('require("foobar")', { filename: '/data/myvmscript.js' }); vm.run(script);

### Resolver

Ein Resolver kann über `makeResolverFromLegacyOptions` erstellt und für mehrere `NodeVM`-Instanzen verwendet werden, wodurch kompilierter Modulcode gemeinsam genutzt werden kann, was die Ladezeiten potenziell verkürzt. Das erste Beispiel von `NodeVM` kann mit `makeResolverFromLegacyOptions` wie folgt neu geschrieben werden.```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

Sie können die Leistung steigern, indem Sie vorkompilierte Skripte verwenden. Das vorkompilierte VMScript kann mehrfach ausgeführt werden. Es ist wichtig zu beachten, dass der Code nicht an eine VM (Kontext) gebunden ist; vielmehr wird er vor jedem Lauf gebunden, nur für diesen Lauf.```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));

Es funktioniert sowohl für `VM` als auch für `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));

Code wird beim ersten Ausführen automatisch kompiliert. Man kann den Code jederzeit mit script.compile() kompilieren. Sobald der Code kompiliert ist, hat die Methode keine Wirkung mehr.

Fehlerbehandlung

Fehler bei der Codekompilierung und bei der synchronen Codeausführung können mit try-catch behandelt werden. Fehler bei der asynchronen Codeausführung können behandelt werden, indem ein uncaughtException-Event-Handler an das process-Objekt von Node angehängt wird.```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); });

## Debuggen von Sandbox-Code

Sie können Code, der in der Sandbox läuft, debuggen oder untersuchen, als ob er in einem normalen Prozess laufen würde.

-   Sie können Haltepunkte verwenden (dies erfordert, dass Sie einen Skriptdateinamen angeben)
-   Sie können das Schlüsselwort `debugger` verwenden.
-   Sie können Step-in verwenden, um in den in der Sandbox laufenden Code zu springen.

### Beispiel

/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;

## Schreibgeschützte Objekte (experimentell)

Um zu verhindern, dass Sandbox-Skripte Eigenschaften der proxied Objekte hinzufügen, ändern oder löschen, können Sie `freeze`-Methoden verwenden, um das Objekt schreibgeschützt zu machen. Dies ist nur innerhalb der VM wirksam. Eingefrorene Objekte sind tiefgehend betroffen. Primitive Typen können nicht eingefroren werden.

**Beispiel ohne Verwendung von `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

Beispiel mit Verwendung von 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

**WICHTIG:** Es ist nicht möglich, Objekte einzufrieren, die bereits per Proxy an die VM übergeben wurden.

## Geschützte Objekte (experimentell)

Im Gegensatz zu `freeze` erlaubt diese Methode Sandbox-Skripten, Eigenschaften an Objekten hinzuzufügen, zu ändern oder zu löschen, mit einer Ausnahme - es ist nicht möglich, Funktionen anzuhängen. Sandbox-Skripte sind daher nicht in der Lage, Methoden wie `toJSON`, `toString` oder `inspect` zu modifizieren.

**WICHTIG:** Es ist nicht möglich, Objekte zu schützen, die bereits per Proxy an die VM übergeben wurden.

## Beziehungen zwischen Sandboxen```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

Bevor Sie vm2 in der Kommandozeile verwenden können, installieren Sie es global mit npm install vm2 -g.```sh vm2 ./script.js

## Härtungsempfehlungen

vm2 verhindert Sandbox-Escapes (nicht vertrauenswürdiger Code, der Zugriff auf den Host-Realm erlangt). Es verhindert **nicht** von sich aus jede Form von Ressourcenerschöpfung oder Denial-of-Service. Wer die Sandbox einbettet und nicht vertrauenswürdigen Code ausführt, sollte die folgenden mehrschichtigen Schutzmaßnahmen um die Sandbox herum ergänzen.

### 1. Speicherzuweisung mit `bufferAllocLimit` begrenzen

Ein einzelner `Buffer.alloc(N)`-Aufruf mit einem angreiferkontrollierten `N` läuft als eine synchrone Host-C++-Zuweisung, die von V8s `timeout` nicht unterbrochen werden kann. In speicherbeschränkten Umgebungen kann ein ~100-Byte-Sandbox-Payload einen Host-RSS-Sprung von über 100 MB verursachen und den Host-Prozess durch OOM zum Absturz bringen. Setzen Sie `bufferAllocLimit` (z. B. `32 * 1024 * 1024`), um einzelne Zuweisungen zu begrenzen:```js
const vm = new VM({
	timeout: 1000,
	bufferAllocLimit: 32 * 1024 * 1024,
	allowAsync: false,
});

Die Obergrenze gilt auch für die veralteten Pfade Buffer(N) und new Buffer(N). Beachten Sie, dass eine aggregierte Erschöpfung (viele kleine Allokationen, Buffer.concat, Uint8Array, String.repeat, Array(n).fill() usw.) nicht durch diese Obergrenze abgedeckt ist – kombinieren Sie sie mit einem Host-seitigen Speicherlimit (--max-old-space-size, Container-Limit, cgroup) für eine vollständige Abdeckung.

2. Installieren Sie einen Host-seitigen unhandledRejection-Handler

Es gibt eine Klasse von Host-Prozess-Abbruch-DoS, bei der Sandbox-Code eine async function, async function* oder await using erstellt, deren Rumpf einen Wert wirft, der während der Stack-Formatierung einen Host-Realm-Fehler auslöst (z. B. e.name = Symbol(); e.stack). V8 erstellt das Ablehnungs-Promise über das intrinsische Promise des Realms, was den Promise-Unterklassen-Wrapper von vm2 umgeht, sodass die Ablehnung als unhandledRejection an den Host entkommt. Auf Node 15+ ist das Standardverhalten, den Prozess zu beenden.

Um dies zu schließen, muss das beobachtbare Host-Verhalten geändert werden, daher liefert vm2 standardmäßig keinen Fix. Einbettende Anwendungen sollten einen Prozess-Level-Handler installieren, der Ablehnungen aus der Sandbox schluckt (oder protokolliert):```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); });

Wenn Ihre Anwendung keine andere Quelle für unbehandelte Ablehnungen hat, ist ein pauschales Schlucken + Protokollieren akzeptabel:```js
process.on('unhandledRejection', reason => {
	yourLogger.warn('swallowed sandbox rejection', reason);
});

Ein gezielter Fix könnte in einem zukünftigen Minor-Release hinter einem Opt-in-Flag swallowSandboxUnhandledRejections ausgeliefert werden; bis dahin ist der Host-seitige Handler die empfohlene Gegenmaßnahme.

3. Mit einem Speicherlimit auf Prozessebene ausführen

Selbst mit gesetztem bufferAllocLimit sollte der Host-Prozess mit --max-old-space-size (oder einem entsprechenden Container-Speicherlimit) ausgeführt werden, das auf die Arbeitslast abgestimmt ist. Das Limit schützt vor der Einzelallokations-Primitive; das Betriebssystem-Limit schützt vor aggregierter Erschöpfung und vor jeder zukünftigen Allokations-Primitive, die vm2 noch nicht begrenzt hat.

4. require.builtin: ['*'] als Nicht-Sandbox-Konfiguration behandeln

Der Platzhalter '*' erweitert sich auf die meisten Node-Built-ins, einschließlich child_process, fs, dgram, net, http und dns. Dabei handelt es sich um Primitiven mit vollständigen Host-Fähigkeiten — require('child_process').execSync('id') ist unter '*' aus der Sandbox erreichbar. Die '*'-Semantik von vm2 ist beabsichtigt (in manchen Einbettungsszenarien wird vertrauenswürdiger, aber isolierter Code ausgeführt), sollte aber nicht als Standard für nicht vertrauenswürdigen Code verwendet werden. Bevorzuge eine explizite Allowlist mit der kleinsten Menge an Modulen, die deine Sandbox tatsächlich benötigt.

5. nesting: true ist ein Notausstieg

nesting: true ermöglicht es Sandbox-Code, require('vm2') aufzurufen und verschachtelte NodeVMs zu erstellen. Die require-Konfiguration der verschachtelten VM wird von dem Sandbox-Code gewählt, der sie erstellt, und nicht durch die äußere VM eingeschränkt. Konkret:```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);

Wenn Sie `nesting: true` setzen, haben Sie der Sandbox faktisch dieselbe Vertrauensstufe eingeräumt wie sich selbst. **Aktivieren Sie `nesting: true` nicht für nicht vertrauenswürdigen Code.** Verwenden Sie es nur, wenn Sie dem Code in der Sandbox selbst vertrauen, aber aus nicht sicherheitsbezogenen Gründen VM-artige Ausführungssemantik (neuer globaler Kontext, kontrollierte Timeouts) wünschen.

`nesting: true` **erfordert ein explizites `require`-Konfigurationsobjekt** (z. B. `require: { builtin: [] }` oder `require: {}`). Jede andere Form — `require: false`, `require: undefined`, `require: null` oder das vollständige Weglassen von `require` — wirft `VMError` beim Erstellen (GHSA-m4wx-m65x-ghrr, ersetzt GHSA-8hg8-63c5-gwmx). Alle diese Formen erzeugen einen ausschließlich auf NESTING_OVERRIDE beschränkten Resolver: Die Sandbox kann `require('vm2')` verwenden, aber sonst nichts, was eine reine Escape-Primitive ohne legitime Verwendung darstellt. Um alle Requires zu verweigern, entfernen Sie `nesting: true`. Um verschachtelte VMs zu erlauben, geben Sie eine explizite `require`-Konfiguration an, damit der Kompromiss an der Aufrufstelle sichtbar ist.

## Bekannte Probleme

-   Es ist nicht möglich, eine Klasse zu definieren, die eine proxierte Klasse erweitert. Dies schließt die Verwendung einer proxierten Klasse in `Object.create` ein.
-   Direktes eval funktioniert nicht.
-   Beim Protokollieren von Sandbox-Arrays wird der Array-Teil in den Eigenschaften wiederholt.
-   Quellcode-Transformationen können zu einer anderen Quellzeichenfolge für eine Funktion führen.
-   Es gibt Möglichkeiten, den Node-Prozess von innerhalb der Sandbox zum Absturz zu bringen. Siehe [Härtungsempfehlungen](#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

Kategorien