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 die Whitelist gesetzten eingebauten Node-Modulen ausführen kann.

Installation```sh

npm install vm2

## Schnellbeispiele```js
import { VM } from 'vm2';

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

To install `nuclei`, you need [Go](https://golang.org/dl/) installed on your system. Then you can install it with the following command:

```bash
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

Alternatively, you can download the pre-built binaries from the Releases page.

Docker

You can also run nuclei using Docker:

docker pull projectdiscovery/nuclei:latest
docker run -it projectdiscovery/nuclei:latest

Homebrew

If you are on macOS or Linux, you can install nuclei via Homebrew:

brew install nuclei

Usage

nuclei -h

This will display help for the tool. Here are all the switches it supports.

Usage:
  nuclei [flags]

Flags:
INPUT:
   -u, -target string[]          target URLs/hosts to scan
   -l, -list string              path to file containing a list of target URLs/hosts to scan (one per line)
   -resume string                resume scan using resume.cfg (clustering will be disabled)
   -sa, -scan-all-ips            scan all the IP's associated with DNS record
   -health-check                 run diagnostic check up
``````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',
);

Wichtiger Sicherheitshinweis

Bevor Sie vm2 verwenden, sollten Sie verstehen, wie es funktioniert und welche Einschränkungen es hat.

vm2 versucht, nicht vertrauenswürdigen JavaScript-Code im selben Node.js-Prozess wie Ihre Anwendung zu sandboxen. Dies geschieht über ein komplexes Netzwerk von 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. Objekte können über Prototyp-Ketten erreicht werden, Konstruktoren können über Fehlerobjekte erreicht werden, 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 bezüglich dieser Realität: Trotz unserer besten Bemühungen entdecken Forscher und Sicherheitsexperten kontinuierlich neue Wege, die vm2-Sandbox zu umgehen. Wir patchen diese Schwachstellen aktiv, sobald sie gemeldet werden, aber die Natur des Katz-und-Maus-Spiels bei In-Process-Sandboxing bedeutet:

  1. Neue Umgehungen werden wahrscheinlich in Zukunft entdeckt. Prüfen Sie unsere Sicherheitshinweise auf bekannte Schwachstellen.
  2. Sie müssen vm2 aktualisiert halten, um von den neuesten Sicherheitsfixes zu profitieren. Abonnieren Sie Sicherheitshinweise und aktualisieren Sie umgehend.
  3. vm2 sollte nicht Ihre einzige Verteidigungslinie sein. Defense in Depth ist unerlässlich, wenn Sie nicht vertrauenswürdigen Code ausführen.

Robustere Alternativen

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

LösungAnsatzLeistungKompromisse
isolated-vmSeparate V8-Isolate (verschiedene V8-Heaps)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 DiensteCloud-basierte Code-Ausführung (z. B. AWS Lambda, Cloudflare Workers)VariabelNetzwerklatenz; externe Abhängigkeit

Wann vm2 möglicherweise weiterhin geeignet ist

vm2 kann geeignet sein, wenn:

  • Sie eine enge Integration mit Host-Objekten und 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 (Netzwerk-Isolation, Dateisystem-Einschränkungen, Ressourcenlimits)
  • Sie das Risiko akzeptieren und aktiv auf Sicherheitsupdates achten

Wenn Sie Code aus vollständig nicht vertrauenswürdigen Quellen ausführen (z. B. beliebige Benutzereinsendungen), empfehlen wir dringend eine Lösung mit stärkeren Isolationsgarantien.

Laufzeitumgebungen

LaufzeitumgebungStatus
Node.jsUnterstützt. Die Sandbox ist eine Sicherheitsgrenze.
BunExperimentell. Teilweise funktionale Kompatibilität — keine Sicherheitsgrenze.

Für Bun gelten zwei getrennte Einschränkungen, und keine impliziert die andere.

Es ist keine Sicherheitsgrenze. Das Bedrohungsmodell von vm2, der Angriffskatalog in docs/ATTACKS.md und jeder Regressionstest in test/ghsa/ leiten sich aus V8-Interna ab. JavaScriptCore, das Bun verwendet, hat seine eigenen Äquivalente, und keines wurde gegen die vm2-Brücke geprüft. Das Bestehen der Testsuite unter Bun zeigt Kompatibilität, nicht dass die Sandbox dort hält. Verwenden Sie vm2 unter Bun nicht, um nicht vertrauenswürdigen Code zu isolieren.

Die Kompatibilität ist teilweise, nicht gleichwertig. Ein grüner Bun-Lauf deckt nur die Tests ab, die dort tatsächlich ausgeführt werden. test/bun-skips.js listet auf, was ausgeschlossen ist und warum, und die bekannten Verhaltenslücken umfassen:

  • Buffer.from(arrayLike) gibt einen Puffer mit der Länge null zurück
  • VMScript-Metadaten für filename / lineOffset / columnOffset sind nicht beobachtbar, da JSC-CallSite-Objekte keine Methoden tragen
  • Object.freeze auf einem eingefrorenen Host-Objekt mit einem nicht konfigurierbaren Accessor wirft einen Proxy-Invariant-TypeError, wo V8 dies nicht tut
  • einige Buffer-Operationen über die Sandbox-Grenze hinweg sind drastisch langsamer — eine 64-MB-allocUnsafe dauert über 400 Sekunden gegenüber 1,7 unter Node, langsam genug, um wie ein Hänger zu wirken

Behandeln Sie die Bun-Unterstützung als Best-Effort-Kompatibilität für vertrauenswürdigen Code und prüfen Sie die Skip-Liste, bevor Sie sich auf ein bestimmtes Verhalten verlassen.

Funktionen

  • Führt nicht vertrauenswürdigen Code sicher in einem einzigen Prozess aus, Seite an Seite mit Ihrem Code
  • 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 (require)
  • Sie können den Zugriff auf bestimmte (oder alle) eingebauten Module einschränken
  • Sie können Methoden sicher aufrufen und Daten und Callbacks zwischen Sandboxes austauschen
  • Aktiv gewartet mit Patches für bekannte Escape-Methoden (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 Einblick in die Interna von vm2, siehe docs/ATTACKS.md.

Was ist der Unterschied zwischen Node's vm 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.');

🛠️ Funktionen

  • Automatische Erkennung: Erkennt automatisch die Zielplattform und wählt die entsprechenden Payloads aus.
  • Verschlüsselung: Unterstützt mehrere Verschlüsselungsalgorithmen, um die Kommunikation zu sichern.
  • Modularer Aufbau: Plugins können einfach hinzugefügt oder entfernt werden, ohne den Kern zu beeinträchtigen.
  • Protokollierung: Detaillierte Protokolle aller Aktivitäten für Audits und Fehlerbehebung.
  • Plattformübergreifend: Funktioniert auf Windows, Linux und macOS.

📦 Installation

git clone https://github.com/example/tool.git
cd tool
pip install -r requirements.txt

🚀 Schnellstart

python tool.py --target 192.168.1.1 --port 8080

⚙️ Konfiguration

Die Konfigurationsdatei befindet sich unter config.yaml. Hier können Sie Ports, Timeouts und andere Parameter anpassen.

server:
  host: 0.0.0.0
  port: 8080
  timeout: 30

📚 Dokumentation

Weitere Informationen finden Sie in der offiziellen Dokumentation.

🤝 Beiträge

Beiträge sind willkommen! Bitte lesen Sie die CONTRIBUTING.md für Richtlinien.

📄 Lizenz

Dieses Projekt ist unter der MIT-Lizenz lizenziert – siehe LICENSE für Details.

import { VM } from 'vm2';

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

-   [VM](#vm)
-   [NodeVM](#nodevm)
-   [VMScript](#vmscript)
-   [Fehlerbehandlung](#fehlerbehandlung)
-   [Debugging von Sandbox-Code](#debugging-eines-sandbox-codes)
-   [Schreibgeschützte Objekte](#schreibgeschuetzte-objekte-experimentell)
-   [Geschützte Objekte](#geschuetzte-objekte-experimentell)
-   [Beziehungen zwischen Sandboxes](#beziehungen-zwischen-sandboxes)
-   [CLI](#cli)
-   [Änderungen von 2.x zu 3.x](https://github.com/patriksimek/vm2/wiki/2.x-to-3.x-changes)
-   [Dokumentation für 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 eingebaute JavaScript-Objekte und Nodes `Buffer` sind verfügbar. Planungsfunktionen (`setInterval`, `setTimeout` und `setImmediate`) sind standardmäßig nicht verfügbar.

**Optionen:**

-   `timeout` - Skript-Timeout in Millisekunden. **WARNUNG**: Sie sollten diese Option möglicherweise zusammen mit `allowAsync=false` verwenden. Darüber hinaus kann die Arbeit mit zurückgegebenen Objekten aus der Sandbox beliebigen Code ausführen und den Timeout umgehen. Man sollte testen, ob das zurückgegebene Objekt ein primitiver Wert ist, indem man `typeof` verwendet, und es im anderen Fall vollständig verwerfen (auch das Protokollieren oder das Erstellen von Fehlermeldungen mit einem solchen Objekt könnte 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 Sie den Compiler vorinstalliert haben, wenn der Wert auf `typescript` oder `coffeescript` gesetzt ist. **`typescript` erfordert `typescript@6` oder früher** — siehe [Compiler](#compiler).
-   `eval` - Wenn auf `false` gesetzt, werfen alle Aufrufe von `eval` oder Funktionskonstruktoren (`Function`, `GeneratorFunction`, usw.) 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 von innerhalb der Sandbox. Anfragen, die dieses Limit überschreiten, werfen synchron einen `RangeError`, ohne die Host-Zuweisung durchzuführen. Standard: `Infinity` (kein Limit, vollständig abwärtskompatibel). Einbettende Systeme, 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, genauso wie sie sich für `timeout` entscheiden. Siehe [Härtungsempfehlungen](#haertungsempfehlungen) 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
```
Du kannst 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` ermöglicht `NodeVM` das Einbinden von Modulen auf die gleiche Weise wie im regulären Node-Kontext.

**Optionen:**

-   `console` – `inherit` zum Aktivieren der Konsole, `redirect` zum Umleiten an Events, `off` zum Deaktivieren der Konsole (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 vorinstalliert ist, wenn der Wert auf `typescript` oder `coffeescript` gesetzt ist. **`typescript` erfordert `typescript@6` oder früher** – siehe [Compiler](#compilers).
-   `eval` – Wenn auf `false` gesetzt, werfen alle Aufrufe von `eval` oder Funktionskonstruktoren (`Function`, `GeneratorFunction`, usw.) 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.
-   `bufferAllocLimit` – Gleiche Semantik wie bei `VM` – maximale Größe in Bytes für eine einzelne `Buffer.alloc`-Familienanfrage von innerhalb der Sandbox. Standard: `Infinity`. Siehe [Härtungsempfehlungen](#hardening-recommendations).
-   `sourceExtensions` – Array von Dateierweiterungen, die als Quellcode behandelt werden (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 mit `/node_modules/${beliebiges_erlaubtes_externes_modul}/(?!/node_modules/)` übereinstimmen, dürfen eingebunden werden.
-   `require.external.modules` – Array erlaubter externer Module. Unterstützt auch Wildcards, sodass die Angabe von `['@scope/*-ver-??]` beispielsweise die Verwendung aller Module mit einem Namen der Form `@scope/something-ver-aa`, `@scope/other-ver-11` usw. erlaubt. Der `*`-Wildcard entspricht nicht Pfadtrennzeichen.
-   `require.external.transitive` – Boolescher Wert, der angibt, ob transitive Abhängigkeiten externer Module erlaubt sind (Standard: `false`). **WARNUNG**: Wenn ein Modul transitiv eingebunden wird, kann jedes Modul es anschließend normal einbinden, selbst 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änkte Pfade, aus denen lokale Module eingebunden 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 einzubinden und sie in die Sandbox zu proxien. `sandbox`, um Module in der Sandbox zu laden, zu kompilieren und einzubinden. `callback(moduleFilename, ext)`, um pro Modul dynamisch einen Kontext zu wählen. Der Standard ist `sandbox`, wenn nichts angegeben ist. Mit Ausnahme von `events` werden eingebaute Module immer im Host eingebunden und in die Sandbox geproxiert.
-   `require.import` – Ein Array von Modulen, die beim Start in die NodeVM geladen werden.
-   `require.resolve` – Eine zusätzliche Lookup-Funktion für den Fall, dass ein Modul in keinem der traditionellen Node-Lookup-Pfade gefunden wurde.
-   `require.customRequire` – Wird anstelle der `require`-Funktion verwendet, um Module aus dem Host zu laden.
-   `require.strict` – `false`, um den strikten Modus für Module, die per `require` geladen werden, 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 beliebige Host-Module einbinden kann. `true`, um VM-Verschachtelung zu aktivieren (Standard: `false`).
-   `wrapper` – `commonjs` (Standard), um das Skript in einen CommonJS-Wrapper zu packen, `none`, um den vom Skript zurückgegebenen Wert abzurufen.
-   `argv` – Array, das an `process.argv` übergeben wird.
-   `env` – Objekt, das an `process.env` übergeben wird.
-   `strict` – `true`, um geladene Module im strikten Modus auszuführen (Standard: `false`).

**WICHTIG**: Timeout ist für NodeVM nicht wirksam, daher ist es nicht immun gegen `while (true) {}` oder ähnliches Übel.

**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**: Weitere Verwendungsbeispiele finden Sie in den Tests.

### Module über relative Pfade laden

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 und möglicherweise die Ladezeiten verkürzt werden. 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 automatisch kompiliert, sobald es zum ersten Mal ausgeführt wird. Man kann den Code jederzeit mit `script.compile()` kompilieren. Sobald der Code kompiliert ist, hat die Methode keine Wirkung mehr.

## Compiler

`compiler` akzeptiert `javascript` (Standard), `typescript`, `coffeescript` oder eine eigene Funktion. Die `typescript`- und `coffeescript`-Compiler sind optional – installiere das Paket selbst; vm2 hängt von keinem der beiden ab.

### TypeScript

**Der eingebaute `typescript`-Compiler erfordert `typescript@6` oder früher.**

vm2 transpiliert über die `transpileModule()`-API von TypeScript. TypeScript 7 hat sie aus dem Paket-Einstiegspunkt entfernt – `require('typescript')` löst dort nur noch zu `{ version, versionMajorMinor }` auf, und die Ersatz-API liegt hinter den ausdrücklich als instabil markierten `typescript/unstable/*`-Unterpfaden, von denen keiner ein Einzeldatei-Transpile-Äquivalent bietet. Es gibt daher nichts, auf das vm2 bei 7.x zurückfallen könnte.

Die Auswahl von `compiler: 'typescript'` mit installiertem TypeScript 7 wirft bei `new VMScript(...)` / `new VM(...)` einen Fehler:```
VMError: The installed TypeScript (7.0.2) does not expose the transpileModule() API that
vm2's built-in TypeScript compiler uses; it was removed from the package entry point in
TypeScript 7. Install typescript@6 or earlier, or pass your own transpiler as a function:
{ compiler: (code, filename) => javaScriptSource }.
```
Entweder pinne `typescript@6` oder stelle deinen eigenen Transpiler bereit – jede Funktion, die JavaScript zurückgibt, funktioniert, also sind TypeScript 7s `tsc`, esbuild, swc oder ein Type-Stripper alle gültig:```js
import { VM, VMScript } from 'vm2';
import { transformSync } from 'esbuild';

const script = new VMScript('const x: number = 1; x', {
	compiler: (code, filename) => transformSync(code, { loader: 'ts', format: 'cjs' }).code,
});

new VM().run(script);
```
Ein benutzerdefinierter Compiler empfängt `(code, filename)` und muss JavaScript-Quellcode zurückgeben. Er läuft **in der Host-Umgebung, vor der Sandboxing** — behandeln Sie ihn als vertrauenswürdigen Code und bauen Sie niemals einen aus nicht vertrauenswürdiger Eingabe.

### CoffeeScript

Erfordert, dass `coffee-script` installiert ist. Kompiliert mit `{ header: false, bare: true }`; alle `compilerOptions`, die Sie übergeben, werden darüber zusammengeführt.

## Fehlerbehandlung

Fehler bei der Codekompilierung und 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 den `process` 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);
});
```
## Debugging von Sandbox-Code

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

-   Sie können Haltepunkte verwenden (dazu müssen Sie einen Skriptdateinamen angeben).
-   Sie können das Schlüsselwort `debugger` verwenden.
-   Sie können Schritt-für-Schritt (Step-in) verwenden, um in den in der Sandbox laufenden Code einzusteigen.

### 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 werden tiefgreifend beeinflusst. 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 an die VM weitergeleitet (proxied) wurden.

## Geschützte Objekte (experimentell)

Im Gegensatz zu `freeze` erlaubt diese Methode Sandbox-Skripten, Eigenschaften von Objekten hinzuzufügen, zu ändern oder zu löschen – mit einer Ausnahme: Es ist nicht möglich, Funktionen anzuhängen. Sandbox-Skripte können daher keine Methoden wie `toJSON`, `toString` oder `inspect` modifizieren.

**WICHTIG:** Es ist nicht möglich, Objekte zu schützen, die bereits an die VM weitergeleitet (proxied) wurden.

## Beziehungen zwischen Sandboxes```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 du vm2 in der Befehlszeile verwenden kannst, installiere es global mit `npm install vm2 -g`.```sh
vm2 ./script.js
```
## Härtungsempfehlungen

vm2 verhindert Sandbox-Escapes (nicht vertrauenswürdiger Code, der Host-Realm-Zugriff erlangt). Es verhindert jedoch **nicht** von sich aus jede Form von Ressourcenerschöpfung oder Denial-of-Service. Einbettende Anwendungen, die nicht vertrauenswürdigen Code ausführen, sollten die folgenden mehrschichtigen Abwehrmaßnahmen um die Sandbox herum hinzufügen.

### 1. Speicherzuweisung mit `bufferAllocLimit` begrenzen

Ein einzelner `Buffer.alloc(N)`-Aufruf mit einem vom Angreifer kontrollierten `N` läuft als eine synchrone Host-C++-Zuweisung, die das `timeout` von V8 nicht unterbrechen kann. In speicherbegrenzten Umgebungen kann eine ~100-Byte-Sandbox-Payload einen RSS-Sprung des Hosts 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** von dieser Obergrenze abgedeckt ist – kombinieren Sie sie für eine vollständige Abdeckung mit einem hostseitigen Speicherlimit (`--max-old-space-size`, Container-Limit, cgroup).

### 2. Installieren Sie einen hostseitigen `unhandledRejection`-Handler

Es existiert 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 Fehler in der Host-Realm auslöst (z. B. `e.name = Symbol(); e.stack`). V8 erstellt das Rejection-Promise über das intrinsische Promise der Realm, was den `Promise`-Subklassen-Wrap von vm2 umgeht, sodass die Rejection als `unhandledRejection` zum Host entkommt. Unter Node 15+ ist das Standardverhalten, den Prozess zu beenden.

Das Schließen dieser Lücke erfordert eine Änderung des beobachtbaren Host-Verhaltens, daher liefert vm2 standardmäßig keinen Fix. Embedder sollten einen Prozess-Level-Handler installieren, der aus der Sandbox stammende Rejections verschluckt (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);
});
```
Eine gezielte Korrektur 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. Ausführung mit einem Prozessweiten Speicherlimit

Selbst wenn `bufferAllocLimit` gesetzt ist, 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 Primitive für einzelne Allokationen; das OS-Level-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 Wildcard `'*'` erweitert sich auf die meisten Node-Built-ins, einschließlich `child_process`, `fs`, `dgram`, `net`, `http` und `dns`. Dies sind vollwertige Host-Fähigkeits-Primitiven — `require('child_process').execSync('id')` ist unter `'*'` aus der Sandbox erreichbar. Die `'*'`-Semantik von vm2 ist beabsichtigt (einige Embedder führen vertrauenswürdigen, aber isolierten Code aus), sollte jedoch nicht als Standard für nicht vertrauenswürdigen Code verwendet werden. Bevorzugen Sie eine explizite Allowlist mit der kleinsten Menge an Modulen, die Ihre Sandbox tatsächlich benötigt.

### 5. `nesting: true` ist eine Escape-Hatch

`nesting: true` erlaubt Sandbox-Code, `require('vm2')` aufzurufen und verschachtelte NodeVMs zu konstruieren. **Die `require`-Konfiguration der verschachtelten VM wird vom Sandbox-Code gewählt, der sie konstruiert, 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 effektiv die gleiche Vertrauensstufe eingeräumt wie sich selbst. **Aktivieren Sie `nesting: true` nicht für nicht vertrauenswürdigen Code.** Verwenden Sie es nur, wenn Sie dem sandboxierten Code selbst vertrauen, aber aus nicht-sicherheitsrelevanten Gründen VM-artige Ausführungssemantik (frisches globales Objekt, 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 beim Erstellen einen `VMError` (GHSA-m4wx-m65x-ghrr, ersetzt GHSA-8hg8-63c5-gwmx). Alle diese Formen erzeugen einen reinen NESTING_OVERRIDE-Resolver: Die Sandbox kann `require('vm2')` ausführen, 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 beinhaltet die Verwendung einer proxierten Klasse in `Object.create`.
-   Direktes `eval` funktioniert nicht.
-   Beim Protokollieren von Sandbox-Arrays wird der Array-Teil in den Eigenschaften wiederholt.
-   Quellcode-Transformationen können zu einem anderen Quellstring 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).
-   Der eingebaute `typescript`-Compiler funktioniert nicht mit TypeScript 7 oder neuer, da dort die `transpileModule()`-API, die vm2 verwendet, entfernt wurde. Verwenden Sie `typescript@6` oder übergeben Sie Ihren eigenen Transpiler — siehe [Compiler](#compilers).

[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