Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
vm2 — Sandbox JavaScript isolée pour Node.js qui exécute du code non fiable avec un accès restreint aux modules intégrés et aux ressources hôte via une interception basée sur Proxy. | Kitploit
Outils/GitHubGitHub/patriksimek/vm2
Analyse Dynamique (Sandboxing)Analyse de CodeVirtualisation de SécuritéUtilitaires et Frameworks
GitHubpatriksimek/vm2

vm2

Sandbox JavaScript isolée pour Node.js qui exécute du code non fiable avec un accès restreint aux modules intégrés et aux ressources hôte via une interception basée sur Proxy.

Voir le dépôt
4.1k326il y a 6 joursVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

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 est un sandbox capable d’exécuter du code non fiable avec les modules intégrés de Node en liste blanche.

Avertissement de sécurité important

Avant d’utiliser vm2, vous devez comprendre comment il fonctionne et quelles sont ses limites.

vm2 tente de mettre en sandbox du code JavaScript non fiable dans le même processus Node.js que votre application. Pour ce faire, il s’appuie sur un réseau complexe de Proxies qui intercepte et gère chaque interaction entre le sandbox et l’environnement hôte.

Le défi fondamental

JavaScript est un langage extraordinairement dynamique. Les objets peuvent être atteints via les chaînes de prototypes, les constructeurs peuvent être atteints via des objets d’erreur, les symboles fournissent des hooks de protocole, et l’exécution asynchrone crée des fenêtres temporelles. Le nombre considérable de façons de passer d’un objet à un autre en JavaScript rend extrêmement difficile la construction d’un sandbox in-process hermétique.

Nous sommes honnêtes quant à cette réalité : Malgré tous nos efforts, les chercheurs et les professionnels de la sécurité découvrent continuellement de nouvelles façons de s’échapper du sandbox de vm2. Nous corrigeons activement ces vulnérabilités dès qu’elles sont signalées, mais la nature de « chat et de la souris » du sandboxing in-process implique que :

  1. De nouveaux contournements seront probablement découverts à l’avenir. Consultez nos avis de sécurité pour les vulnérabilités connues.
  2. Vous devez maintenir vm2 à jour pour bénéficier des derniers correctifs de sécurité. Abonnez-vous aux avis de sécurité et mettez à jour rapidement.
  3. vm2 ne doit pas être votre seule ligne de défense. La défense en profondeur est essentielle lors de l’exécution de code non fiable.

Alternatives plus robustes

Si vous avez besoin de garanties d’isolation plus fortes, envisagez ces alternatives qui offrent une véritable isolation au niveau du processus ou du matériel :

Quand vm2 peut encore être approprié

vm2 peut être approprié lorsque :

  • Vous avez besoin d’une intégration étroite avec les objets hôtes et d’une communication synchrone rapide
  • Le code non fiable provient d’une source relativement fiable (par ex., outils internes, systèmes de plugins avec auteurs vérifiés)
  • Vous combinez vm2 avec d’autres couches de sécurité (isolation réseau, restrictions du système de fichiers, limites de ressources)
  • Vous acceptez le risque et surveillez activement les mises à jour de sécurité

Si vous exécutez du code provenant de sources totalement non fiables (par ex., soumissions d’utilisateurs arbitraires), nous recommandons vivement d’utiliser une solution offrant des garanties d’isolation plus fortes.

Fonctionnalités

  • Exécute du code non fiable en toute sécurité dans un seul processus, côte à côte avec votre code
  • Contrôle total sur la sortie console du sandbox
  • Le sandbox a un accès limité aux méthodes du processus
  • Il est possible de charger des modules (intégrés et externes) depuis le sandbox
  • Vous pouvez limiter l’accès à certains (ou tous) modules intégrés
  • Vous pouvez appeler des méthodes en toute sécurité et échanger des données et des callbacks entre les sandboxes
  • Maintenu activement avec des correctifs pour les méthodes d’évasion connues (voir Avertissement de sécurité)
  • Prise en charge du transpileur

Comment cela fonctionne

  • Il utilise le module VM interne pour créer un contexte sécurisé.
  • Il utilise des Proxies pour empêcher toute évasion du sandbox.
  • Il remplace le require intégré pour contrôler l’accès aux modules.

Pour un examen approfondi des composants internes de vm2, consultez le fichier CONTRIBUTING.md.

Quelle est la différence entre le vm de Node et vm2 ?

Essayez par vous-même :```js import { runInNewContext } from "node:vm";

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

root@kitploit:~
I don't see any content to translate in your message — the `INPUT:` section is empty. Please provide the actual Markdown chunk (chunk 3/51) you'd like translated into French, and I'll process it according to your rules.```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

root@kitploit:~
## Exemples rapides```js
import { VM } from 'vm2';

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

---```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', );

root@kitploit:~
## Documentation

-   [VM](#vm)
-   [NodeVM](#nodevm)
-   [VMScript](#vmscript)
-   [Gestion des erreurs](#error-handling)
-   [Débogage d'un code en bac à sable](#debugging-a-sandboxed-code)
-   [Objets en lecture seule (expérimental)](#read-only-objects-experimental)
-   [Objets protégés (expérimental)](#protected-objects-experimental)
-   [Relations entre bacs à sable](#cross-sandbox-relationships)
-   [CLI](#cli)
-   [Changements entre 2.x et 3.x](https://github.com/patriksimek/vm2/wiki/2.x-to-3.x-changes)
-   [Documentation 1.x et 2.x](https://github.com/patriksimek/vm2/wiki/1.x-and-2.x-docs)
-   [Contribuer](https://github.com/patriksimek/vm2/wiki/Contributing)

## VM

VM est un bac à sable simple permettant d'exécuter de manière synchrone du code non fiable sans la fonctionnalité `require`. Seuls les objets natifs de JavaScript et le `Buffer` de Node sont disponibles. Les fonctions de temporisation (`setInterval`, `setTimeout` et `setImmediate`) ne sont pas disponibles par défaut.

**Options :**

-   `timeout` - Délai d'exécution du script en millisecondes. **ATTENTION** : Vous voudrez peut-être utiliser cette option avec `allowAsync=false`. De plus, manipuler les objets renvoyés par le bac à sable peut entraîner l'exécution de code arbitraire et contourner le délai d'attente. Il faut vérifier si l'objet renvoyé est une primitive à l'aide de `typeof` et l'écarter complètement (journaliser ou créer des messages d'erreur avec un tel objet peut également exécuter à nouveau du code arbitraire) dans le cas contraire.
-   `sandbox` - L'objet global de VM.
-   `compiler` - `javascript` (par défaut), `typescript`, `coffeescript` ou une fonction de compilation personnalisée. La bibliothèque s'attend à ce que le compilateur soit préinstallé si la valeur est définie sur `typescript` ou `coffeescript`.
-   `eval` - Si la valeur est `false`, tout appel à `eval` ou aux constructeurs de fonctions (`Function`, `GeneratorFunction`, etc.) lancera une `EvalError` (par défaut : `true`).
-   `wasm` - Si la valeur est `false`, toute tentative de compilation d'un module WebAssembly lancera une `WebAssembly.CompileError` (par défaut : `true`). Remarque : `WebAssembly.JSTag` est supprimé dans le bac à sable pour des raisons de sécurité, de sorte que le code wasm ne peut pas intercepter les exceptions JavaScript.
-   `allowAsync` - Si la valeur est `false`, toute tentative d'exécuter du code utilisant `async` lancera une `VMError` (par défaut : `true`).
-   `bufferAllocLimit` - Taille maximale en octets pour une seule requête `Buffer.alloc` / `Buffer.allocUnsafe` / `Buffer.allocUnsafeSlow` / `Buffer(N)` / `new Buffer(N)` depuis l'intérieur du bac à sable. Les requêtes qui dépassent ce plafond lèvent une `RangeError` de manière synchrone sans effectuer l'allocation hôte. Par défaut : `Infinity` (aucun plafond, entièrement rétrocompatible). Les intégrateurs qui exécutent du code non fiable dans des environnements à mémoire limitée (Docker / Kubernetes / Lambda / serverless) devraient opter pour un plafond fini (par exemple `32 * 1024 * 1024`) dans le cadre d'une défense DoS en couches, de la même manière qu'ils optent pour `timeout`. Voir [Recommandations de durcissement](#hardening-recommendations) ci-dessous.

**IMPORTANT** : Le délai d'attente n'est effectif que sur le code synchrone que vous exécutez via `run`. Le délai d'attente ne fonctionne **PAS** sur les méthodes renvoyées par VM. Il existe certaines situations où le délai d'attente ne fonctionne pas - voir [#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

Vous pouvez également récupérer des valeurs depuis la VM.```js let number = vm.run('1337'); // returns 1337

root@kitploit:~
**ASTUCE** : Consultez les tests pour plus d'exemples d'utilisation.

## NodeVM

Contrairement à `VM`, `NodeVM` vous permet de charger des modules via `require`, de la même manière que dans le contexte standard de Node.

**Options :**

-   `console` - `inherit` pour activer la console, `redirect` pour rediriger vers les événements, `off` pour désactiver la console (par défaut : `inherit`).
-   `sandbox` - L'objet global de la VM.
-   `compiler` - `javascript` (par défaut), `typescript`, `coffeescript` ou une fonction de compilation personnalisée (qui reçoit le code et son chemin de fichier). La bibliothèque s'attend à ce que le compilateur soit préinstallé si la valeur est définie sur `typescript` ou `coffeescript`.
-   `eval` - Si défini sur `false`, tout appel à `eval` ou aux constructeurs de fonctions (`Function`, `GeneratorFunction`, etc.) lèvera une `EvalError` (par défaut : `true`).
-   `wasm` - Si défini sur `false`, toute tentative de compilation d'un module WebAssembly lèvera une `WebAssembly.CompileError` (par défaut : `true`). Remarque : `WebAssembly.JSTag` est supprimé dans le sandbox pour des raisons de sécurité, donc le code wasm ne peut pas attraper les exceptions JavaScript.
-   `bufferAllocLimit` - Mêmes sémantiques que pour `VM` — taille maximale en octets pour une seule requête de la famille `Buffer.alloc` depuis l'intérieur du sandbox. Par défaut : `Infinity`. Voir [Recommandations de durcissement](#hardening-recommendations).
-   `sourceExtensions` - Tableau d'extensions de fichiers à traiter comme code source (par défaut : `['js']`).
-   `require` - `true`, un objet ou un Resolver pour activer la méthode `require` (par défaut : `false`).
-   `require.external` - Les valeurs peuvent être `true`, un tableau de modules externes autorisés, ou un objet (par défaut : `false`). Tous les chemins correspondant à `/node_modules/${any_allowed_external_module}/(?!/node_modules/)` sont autorisés à être chargés via `require`.
-   `require.external.modules` - Tableau des modules externes autorisés. Prend également en charge les wildcards, ainsi spécifier `['@scope/*-ver-??]`, par exemple, permettra d'utiliser tous les modules ayant un nom de la forme `@scope/something-ver-aa`, `@scope/other-ver-11`, etc. Le wildcard `*` ne correspond pas aux séparateurs de chemins.
-   `require.external.transitive` - Booléen qui indique si les dépendances transitives des modules externes sont autorisées (par défaut : `false`). **AVERTISSEMENT** : Lorsqu'un module est chargé de manière transitive, n'importe quel module peut alors le charger normalement, même si cela n'était pas possible avant son chargement.
-   `require.builtin` - Tableau des modules intégrés autorisés, accepte ["\*"] pour tous (par défaut : aucun). **AVERTISSEMENT** : "\*" peut être dangereux car de nouveaux modules intégrés peuvent être ajoutés.
-   `require.root` - Chemin(s) restreint(s) où les modules locaux peuvent être chargés (par défaut : tous les chemins).
-   `require.mock` - Collection de modules simulés (mock) (externes ou intégrés).
-   `require.context` - `host` (par défaut) pour charger les modules dans l'hôte et les proxifier dans le sandbox. `sandbox` pour charger, compiler et requérir les modules dans le sandbox. `callback(moduleFilename, ext)` pour choisir dynamiquement un contexte par module. La valeur par défaut sera `sandbox` si rien n'est spécifié. À l'exception de `events`, les modules intégrés sont toujours chargés dans l'hôte et proxifiés dans le sandbox.
-   `require.import` - Un tableau de modules à charger dans NodeVM au démarrage.
-   `require.resolve` - Une fonction de recherche supplémentaire au cas où un module ne serait pas trouvé dans l'un des chemins de recherche traditionnels de Node.
-   `require.customRequire` - À utiliser à la place de la fonction `require` pour charger les modules depuis l'hôte.
-   `require.strict` - `false` pour ne pas forcer le mode strict sur les modules chargés par `require` (par défaut : `true`).
-   `require.fs` - Implémentation personnalisée du système de fichiers.
-   `nesting` - **AVERTISSEMENT** : Autoriser ceci est un risque de sécurité, car les scripts peuvent créer une NodeVM qui peut charger n'importe quel module de l'hôte via `require`. `true` pour activer l'imbrication des VM (par défaut : `false`).
-   `wrapper` - `commonjs` (par défaut) pour envelopper le script dans un wrapper CommonJS, `none` pour récupérer la valeur retournée par le script.
-   `argv` - Tableau à passer à `process.argv`.
-   `env` - Objet à passer à `process.env`.
-   `strict` - `true` pour charger les modules en mode strict (par défaut : `false`).

**IMPORTANT** : Le délai d'expiration (timeout) n'a aucun effet sur NodeVM, il n'est donc pas immunisé contre `while (true) {}` ou des malveillances similaires.

**RAPPEL** : Plus vous autorisez de modules, plus votre sandbox devient fragile.```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);
});

Lorsque wrapper est défini sur none, NodeVM se comporte davantage comme VM pour le code synchrone.```js assert.ok(vm.run('return true') === true);

root@kitploit:~
**ASTUCE** : Consultez les tests pour plus d'exemples d'utilisation.

### Charger des modules par chemin relatif

Pour charger des modules par chemin relatif, vous devez passer le chemin complet du script que vous exécutez comme deuxième argument à la méthode `run` de vm si le script est une chaîne de caractères. Le nom de fichier est alors affiché dans toutes les traces de pile générées par le script.```js
vm.run('require("foobar")', '/data/myvmscript.js');

Si le script que vous exécutez est un VMScript, le chemin est donné dans le constructeur VMScript.```js const script = new VMScript('require("foobar")', { filename: '/data/myvmscript.js' }); vm.run(script);

root@kitploit:~
### Résolveur

Un résolveur peut être créé via `makeResolverFromLegacyOptions` et être utilisé pour plusieurs instances de `NodeVM`, permettant de partager le code de module compilé, ce qui peut accélérer les temps de chargement. Le premier exemple de `NodeVM` peut être réécrit en utilisant `makeResolverFromLegacyOptions` comme suit.```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

Vous pouvez augmenter les performances en utilisant des scripts précompilés. Le VMScript précompilé peut être exécuté plusieurs fois. Il est important de noter que le code n'est lié à aucune VM (contexte) ; il est plutôt lié avant chaque exécution, uniquement pour cette exécution.```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));

root@kitploit:~
Cela fonctionne à la fois pour `VM` et `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));

Le code est compilé automatiquement la première fois qu'il s'exécute. On peut compiler le code à tout moment avec script.compile(). Une fois le code compilé, la méthode n'a aucun effet.

Gestion des erreurs

Les erreurs dans la compilation du code et l'exécution synchrone du code peuvent être gérées par try-catch. Les erreurs dans l'exécution asynchrone du code peuvent être gérées en attachant un gestionnaire d'événements uncaughtException au process de 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); });

root@kitploit:~
## Débogage d'un code en bac à sable

Vous pouvez déboguer ou inspecter le code s'exécutant dans le bac à sable comme s'il s'agissait d'un processus normal.

-   Vous pouvez utiliser des points d'arrêt (ce qui nécessite de spécifier un nom de fichier de script)
-   Vous pouvez utiliser le mot-clé `debugger`.
-   Vous pouvez utiliser step-in pour entrer dans le code s'exécutant dans le bac à sable.

### Exemple

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

root@kitploit:~
## Objets en lecture seule (expérimental)

Pour empêcher les scripts sandboxés d'ajouter, de modifier ou de supprimer des propriétés des objets proxy, vous pouvez utiliser les méthodes `freeze` pour rendre l'objet en lecture seule. Cela n'est efficace qu'à l'intérieur de la VM. Les objets figés sont affectés en profondeur. Les types primitifs ne peuvent pas être figés.

**Exemple sans utiliser `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

Exemple d'utilisation de 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

root@kitploit:~
**IMPORTANT :** Il n'est pas possible de geler des objets qui ont déjà été proxysés vers la VM.

## Objets protégés (expérimental)

Contrairement à `freeze`, cette méthode permet aux scripts sandboxés d'ajouter, de modifier ou de supprimer des propriétés sur des objets, à une exception près : il n'est pas possible d'attacher des fonctions. Les scripts sandboxés ne sont donc pas capables de modifier des méthodes comme `toJSON`, `toString` ou `inspect`.

**IMPORTANT :** Il n'est pas possible de protéger des objets qui ont déjà été proxysés vers la VM.

## Relations inter-sandbox```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

Avant de pouvoir utiliser vm2 en ligne de commande, installez-le globalement avec npm install vm2 -g.```sh vm2 ./script.js

root@kitploit:~
## Recommandations de durcissement

vm2 empêche les évasions de sandbox (code non fiable obtenant un accès au realm de l'hôte). Cela ne permet **pas**, en soi, de prévenir toutes les formes d'épuisement des ressources ou de déni de service. Les intégrateurs exécutant du code non fiable devraient ajouter les défenses en couches suivantes autour de la sandbox.

### 1. Limiter l'allocation mémoire avec `bufferAllocLimit`

Un simple appel `Buffer.alloc(N)` avec un `N` contrôlé par l'attaquant s'exécute comme une seule allocation C++ synchrone de l'hôte que le `timeout` de V8 ne peut pas interrompre. Dans les environnements à mémoire limitée, une charge utile de la sandbox d'environ 100 octets peut provoquer un saut de RSS de 100 Mo+ sur l'hôte et faire planter le processus hôte par OOM. Définissez `bufferAllocLimit` (par ex. `32 * 1024 * 1024`) pour plafonner les allocations individuelles :```js
const vm = new VM({
	timeout: 1000,
	bufferAllocLimit: 32 * 1024 * 1024,
	allowAsync: false,
});

Le plafond s'applique également aux chemins obsolètes Buffer(N) et new Buffer(N). Notez que l'épuisement agrégé (nombreuses petites allocations, Buffer.concat, Uint8Array, String.repeat, Array(n).fill(), etc.) n'est pas couvert par ce plafond — combinez-le avec une limite de mémoire côté hôte (--max-old-space-size, limite de conteneur, cgroup) pour une couverture complète.

2. Installer un gestionnaire unhandledRejection côté hôte

Il existe une classe de DoS par abandon du processus hôte où le code du sandbox crée une async function, une async function*, ou un await using dont le corps lève une valeur qui déclenche une erreur du domaine hôte lors du formatage de la pile (par exemple e.name = Symbol(); e.stack). V8 crée la promesse de rejet via la promesse intrinsèque du domaine, ce qui contourne l'encapsulation de la sous-classe Promise de vm2, si bien que le rejet s'échappe vers l'hôte en tant que unhandledRejection. À partir de Node 15+, le comportement par défaut est de terminer le processus.

Fermer cette brèche nécessite de modifier le comportement observable de l'hôte, c'est pourquoi vm2 ne fournit pas de correctif par défaut. Les intégrateurs devraient installer un gestionnaire au niveau du processus qui avale (ou journalise) les rejets provenant du sandbox :```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); });

root@kitploit:~
Si votre application ne possède aucune autre source de rejets non gérés, une interception globale + journalisation est acceptable :```js
process.on('unhandledRejection', reason => {
	yourLogger.warn('swallowed sandbox rejection', reason);
});

Un correctif ciblé pourrait être livré derrière un flag opt-in swallowSandboxUnhandledRejections dans une future version mineure ; en attendant, le gestionnaire côté hôte est l'atténuation recommandée.

3. Exécuter avec une limite mémoire au niveau du processus

Même avec bufferAllocLimit défini, exécutez le processus hôte avec --max-old-space-size (ou une limite mémoire équivalente au niveau du conteneur) dimensionné pour la charge de travail. La limite protège contre la primitive d'allocation unique ; la limite au niveau du système d'exploitation protège contre l'épuisement global et contre toute future primitive d'allocation que vm2 n'a pas encore plafonnée.

4. Traiter require.builtin: ['*'] comme une configuration non-sandbox

Le caractère générique '*' s'étend à la plupart des modules intégrés de Node, notamment child_process, fs, dgram, net, http et dns. Ce sont des primitives à pleine capacité hôte — require('child_process').execSync('id') est accessible depuis la sandbox avec '*'. La sémantique de '*' dans vm2 est intentionnelle (certains intégrateurs exécutent du code de confiance mais isolé), mais elle ne doit pas être utilisée par défaut pour du code non fiable. Privilégiez une liste d'autorisation explicite du plus petit ensemble de modules dont votre sandbox a réellement besoin.

5. nesting: true est une échappatoire

nesting: true permet au code de la sandbox d'utiliser require('vm2') et de construire des NodeVM imbriquées. La configuration require de la VM imbriquée est choisie par le code de la sandbox qui la construit, et n'est pas contrainte par la VM externe. Concrètement :```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);

root@kitploit:~
Si vous définissez `nesting: true`, vous avez en réalité accordé au sandbox le même niveau de confiance que vous. **N'activez pas `nesting: true` pour du code non fiable.** Utilisez-le uniquement lorsque vous faites confiance au code sandboxé lui-même mais que vous souhaitez une sémantique d'exécution de type VM (global frais, timeouts contrôlés) pour des raisons non liées à la sécurité.

`nesting: true` **exige un objet de configuration `require` explicite** (par ex. `require: { builtin: [] }` ou `require: {}`). Toute autre forme — `require: false`, `require: undefined`, `require: null`, ou l'omission complète de `require` — lève une `VMError` à la construction (GHSA-m4wx-m65x-ghrr, remplace GHSA-8hg8-63c5-gwmx). Toutes ces formes produisent un résolveur NESTING_OVERRIDE uniquement : le sandbox peut faire `require('vm2')` mais rien d'autre, ce qui est une primitive d'évasion pure sans usage légitime. Pour refuser tout `require`, retirez `nesting: true`. Pour autoriser des VM imbriquées, fournissez une configuration `require` explicite afin que le compromis soit visible au site d'appel.

## Problèmes connus

-   Il n'est pas possible de définir une classe qui étend une classe proxifiée. Cela inclut l'utilisation d'une classe proxifiée dans `Object.create`.
-   `eval` direct ne fonctionne pas.
-   La journalisation de tableaux sandboxés répète la partie tableau dans les propriétés.
-   Les transformations de code source peuvent produire une chaîne source différente pour une fonction.
-   Il existe des moyens de faire planter le processus node depuis l'intérieur du sandbox. Voir [Recommandations de durcissement](#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
Télécharger l’outil
SolutionApprochePerformancesCompromis
isolated-vmIsolats V8 séparés (tas V8 différent)RapideEn mode maintenance ; nécessite des mises à jour manuelles de V8
Processus séparé / Workerchild_process ou threads Worker avec des permissions limitéesMoyenneSurcharge IPC plus élevée ; les données doivent être sérialisées
Conteneurs / VMDocker, gVisor, FirecrackerLentSurcharge de démarrage ; gourmand en ressources
Services gérésExécution de code dans le cloud (par ex., AWS Lambda, Cloudflare Workers)VariableLatence réseau ; dépendance externe