
Sandbox JavaScript isolato per Node.js che esegue codice non attendibile con accesso limitato ai moduli integrati e alle risorse host tramite intercettazione basata su Proxy.
vm2 è una sandbox che può eseguire codice non attendibile con i moduli built-in di Node consentiti.
Prima di usare vm2, dovresti capire come funziona e quali sono i suoi limiti.
vm2 tenta di isolare codice JavaScript non attendibile all'interno dello stesso processo Node.js della tua applicazione. Lo fa attraverso una complessa rete di Proxy che intercettano e mediano ogni interazione tra la sandbox e l'ambiente host.
JavaScript è un linguaggio straordinariamente dinamico. Gli oggetti possono essere raggiunti attraverso le catene di prototipi, i costruttori possono essere ottenuti tramite gli oggetti di errore, i symbol forniscono hook di protocollo e l'esecuzione asincrona crea finestre temporali. L'enorme numero di modi per passare da un oggetto all'altro in JavaScript rende estremamente difficile costruire una sandbox in-process a prova di fuga.
Siamo onesti su questa realtà: nonostante i nostri migliori sforzi, ricercatori e professionisti della sicurezza scoprono continuamente nuovi modi per evadere dalla sandbox di vm2. Correggiamo attivamente queste vulnerabilità quando vengono segnalate, ma la natura di "gatto e topo" dell'isolamento in-process implica che:
Se hai bisogno di garanzie di isolamento più forti, considera queste alternative che forniscono un vero isolamento a livello di processo o hardware:
vm2 può essere adatto quando:
Se esegui codice proveniente da fonti completamente non attendibili (es. invii arbitrari da parte degli utenti), ti consigliamo vivamente di utilizzare una soluzione con garanzie di isolamento più forti.
Per uno sguardo approfondito agli internals di vm2, consulta il file CONTRIBUTING.md.
Provalo tu stesso:```js import { runInNewContext } from "node:vm";
runInNewContext('this.constructor.constructor("return process")().exit()'); console.log('Never gets executed.');
Arriveremo a come caricarli ed eseguirli, una volta che avremo capito cosa fanno.```js
import { VM } from 'vm2';
new VM().run('this.constructor.constructor("return process")().exit()');
// Throws ReferenceError: process is not defined
npm install vm2
## Esempi rapidi```js
import { VM } from 'vm2';
const vm = new VM();
vm.run(`process.exit()`); // TypeError: process.exit is not a function
Since the input chunk is empty, there is no text to translate.```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',
);
## Documentazione
- [VM](#vm)
- [NodeVM](#nodevm)
- [VMScript](#vmscript)
- [Gestione degli errori](#error-handling)
- [Debug del codice in sandbox](#debugging-a-sandboxed-code)
- [Oggetti di sola lettura](#read-only-objects-experimental)
- [Oggetti protetti](#protected-objects-experimental)
- [Relazioni tra sandbox](#cross-sandbox-relationships)
- [CLI](#cli)
- [Modifiche da 2.x a 3.x](https://github.com/patriksimek/vm2/wiki/2.x-to-3.x-changes)
- [Documentazione 1.x e 2.x](https://github.com/patriksimek/vm2/wiki/1.x-and-2.x-docs)
- [Contributi](https://github.com/patriksimek/vm2/wiki/Contributing)
## VM
VM è una semplice sandbox per eseguire in modo sincrono codice non attendibile senza la funzionalità `require`. Sono disponibili solo gli oggetti incorporati di JavaScript e il `Buffer` di Node. Le funzioni di pianificazione (`setInterval`, `setTimeout` e `setImmediate`) non sono disponibili per impostazione predefinita.
**Opzioni:**
- `timeout` - Timeout dello script in millisecondi. **ATTENZIONE**: Potresti voler usare questa opzione insieme a `allowAsync=false`. Inoltre, operare su oggetti restituiti dalla sandbox può eseguire codice arbitrario e aggirare il timeout. Si dovrebbe verificare se l'oggetto restituito è un primitivo con `typeof` e, in caso contrario, scartarlo completamente (fare logging o creare messaggi di errore con un tale oggetto potrebbe anche eseguire nuovamente codice arbitrario).
- `sandbox` - Oggetto globale della VM.
- `compiler` - `javascript` (predefinito), `typescript`, `coffeescript` o funzione di compilatore personalizzata. La libreria si aspetta che tu abbia il compilatore preinstallato se il valore è impostato su `typescript` o `coffeescript`.
- `eval` - Se impostato su `false`, qualsiasi chiamata a `eval` o ai costruttori di funzioni (`Function`, `GeneratorFunction`, ecc.) genererà un `EvalError` (predefinito: `true`).
- `wasm` - Se impostato su `false`, qualsiasi tentativo di compilare un modulo WebAssembly genererà un `WebAssembly.CompileError` (predefinito: `true`). Nota: `WebAssembly.JSTag` viene rimosso all'interno della sandbox per motivi di sicurezza, quindi il codice wasm non può catturare le eccezioni JavaScript.
- `allowAsync` - Se impostato su `false`, qualsiasi tentativo di eseguire codice usando `async` genererà un `VMError` (predefinito: `true`).
- `bufferAllocLimit` - Dimensione massima in byte per una singola richiesta `Buffer.alloc` / `Buffer.allocUnsafe` / `Buffer.allocUnsafeSlow` / `Buffer(N)` / `new Buffer(N)` dall'interno della sandbox. Le richieste che superano questo limite generano un `RangeError` in modo sincrono senza eseguire l'allocazione host. Predefinito: `Infinity` (nessun limite, completamente retrocompatibile). Gli embedder che eseguono codice non attendibile in ambienti con memoria limitata (Docker / Kubernetes / Lambda / serverless) dovrebbero adottare un limite finito (ad es. `32 * 1024 * 1024`) come parte di una difesa DoS a strati, allo stesso modo in cui adottano `timeout`. Vedi [Raccomandazioni di hardening](#hardening-recommendations) di seguito.
**IMPORTANTE**: Il timeout è efficace solo su codice sincrono eseguito tramite `run`. Il timeout **NON** funziona su alcun metodo restituito dalla VM. Ci sono alcune situazioni in cui il timeout non funziona - vedi [#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
Puoi anche recuperare valori dalla VM.```js let number = vm.run('1337'); // returns 1337
**SUGGERIMENTO**: Consulta i test per ulteriori esempi di utilizzo.
## NodeVM
A differenza di `VM`, `NodeVM` consente di richiedere moduli nello stesso modo in cui si farebbe nel contesto regolare di Node.
**Opzioni:**
- `console` - `inherit` per abilitare la console, `redirect` per reindirizzare agli eventi, `off` per disabilitare la console (default: `inherit`).
- `sandbox` - L'oggetto globale della VM.
- `compiler` - `javascript` (default), `typescript`, `coffeescript` o una funzione compilatore personalizzata (che riceve il codice e il suo percorso file). La libreria si aspetta che tu abbia il compilatore preinstallato se il valore è impostato su `typescript` o `coffeescript`.
- `eval` - Se impostato a `false`, qualsiasi chiamata a `eval` o a costruttori di funzioni (`Function`, `GeneratorFunction`, ecc.) lancerà un `EvalError` (default: `true`).
- `wasm` - Se impostato a `false`, qualsiasi tentativo di compilare un modulo WebAssembly lancerà un `WebAssembly.CompileError` (default: `true`). Nota: `WebAssembly.JSTag` viene rimosso all'interno della sandbox per motivi di sicurezza, quindi il codice wasm non può catturare eccezioni JavaScript.
- `bufferAllocLimit` - Stessa semantica di `VM` — dimensione massima in byte per una singola richiesta della famiglia `Buffer.alloc` dall'interno della sandbox. Default: `Infinity`. Vedi [Raccomandazioni di hardening](#hardening-recommendations).
- `sourceExtensions` - Array di estensioni di file da trattare come codice sorgente (default: `['js']`).
- `require` - `true`, un oggetto o un Resolver per abilitare il metodo `require` (default: `false`).
- `require.external` - I valori possono essere `true`, un array di moduli esterni consentiti, o un oggetto (default: `false`). Tutti i percorsi che corrispondono a `/node_modules/${any_allowed_external_module}/(?!/node_modules/)` possono essere richiesti.
- `require.external.modules` - Array di moduli esterni consentiti. Supporta anche i wildcard, quindi specificare `['@scope/*-ver-??]`, ad esempio, consentirà di utilizzare tutti i moduli con un nome della forma `@scope/something-ver-aa`, `@scope/other-ver-11`, ecc. Il wildcard `*` non corrisponde ai separatori di percorso.
- `require.external.transitive` - Booleano che indica se le dipendenze transitive dei moduli esterni sono consentite (default: `false`). **ATTENZIONE**: Quando un modulo viene richiesto in modo transitivo, qualsiasi modulo può poi richiederlo normalmente, anche se non era possibile prima che fosse caricato.
- `require.builtin` - Array di moduli integrati consentiti, accetta ["\*"] per tutti (default: nessuno). **ATTENZIONE**: "\*" può essere pericoloso perché nuovi moduli integrati possono essere aggiunti.
- `require.root` - Percorso/i ristretto/i in cui i moduli locali possono essere richiesti (default: ogni percorso).
- `require.mock` - Collezione di moduli mock (sia esterni che integrati).
- `require.context` - `host` (default) per richiedere moduli nell'host e inoltrarli nella sandbox. `sandbox` per caricare, compilare e richiedere moduli nella sandbox. `callback(moduleFilename, ext)` per scegliere dinamicamente un contesto per ogni modulo. Il default sarà la sandbox se non viene specificato nulla. Ad eccezione di `events`, i moduli integrati vengono sempre richiesti nell'host e inoltrati nella sandbox.
- `require.import` - Un array di moduli da caricare in NodeVM all'avvio.
- `require.resolve` - Una funzione di ricerca aggiuntiva nel caso in cui un modulo non venga trovato in uno dei percorsi di ricerca tradizionali di Node.
- `require.customRequire` - Da usare al posto della funzione `require` per caricare moduli dall'host.
- `require.strict` - `false` per non forzare la modalità strict sui moduli caricati da require (default: `true`).
- `require.fs` - Implementazione personalizzata del file system.
- `nesting` - **ATTENZIONE**: Consentire questo è un rischio per la sicurezza poiché gli script possono creare una NodeVM che può richiedere qualsiasi modulo dell'host. `true` per abilitare l'annidamento delle VM (default: `false`).
- `wrapper` - `commonjs` (default) per avvolgere lo script in un wrapper CommonJS, `none` per recuperare il valore restituito dallo script.
- `argv` - Array da passare a `process.argv`.
- `env` - Oggetto da passare a `process.env`.
- `strict` - `true` per caricare i moduli in modalità strict (default: `false`).
**IMPORTANTE**: Il timeout non è efficace per NodeVM, quindi non è immune a `while (true) {}` o simili nefandezze.
**RICORDA**: Più moduli consenti, più la tua sandbox diventa 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);
});
Quando wrapper è impostato su none, NodeVM si comporta più come VM per codice sincrono.```js
assert.ok(vm.run('return true') === true);
**CONSIGLIO**: Vedi i test per ulteriori esempi di utilizzo.
### Caricare moduli tramite percorso relativo
Per caricare moduli tramite percorso relativo, devi passare il percorso completo dello script che stai eseguendo come secondo argomento al metodo `run` di vm se lo script è una stringa. Il nome del file viene quindi visualizzato in qualsiasi stack trace generato dallo script.```js
vm.run('require("foobar")', '/data/myvmscript.js');
Se lo script che stai eseguendo è un VMScript, il percorso è fornito nel costruttore VMScript.```js const script = new VMScript('require("foobar")', { filename: '/data/myvmscript.js' }); vm.run(script);
### Resolver
Un resolver può essere creato tramite `makeResolverFromLegacyOptions` e può essere utilizzato per più istanze `NodeVM`, consentendo di condividere il codice del modulo compilato e potenzialmente accelerando i tempi di caricamento. Il primo esempio di `NodeVM` può essere riscritto utilizzando `makeResolverFromLegacyOptions` come segue.```js
const resolver = makeResolverFromLegacyOptions({
external: true,
builtin: ['fs', 'path'],
root: './',
mock: {
fs: {
readFileSync: () => 'Nice try!',
},
},
});
const vm = new NodeVM({
console: 'inherit',
sandbox: {},
require: resolver,
});
Puoi aumentare le prestazioni utilizzando script precompilati. Il VMScript precompilato può essere eseguito più volte. È importante notare che il codice non è associato a nessuna VM (contesto); piuttosto, viene associato prima di ogni esecuzione, solo per quella esecuzione.```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));
Funziona sia per `VM` che per `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));
Il codice viene compilato automaticamente la prima volta che viene eseguito. Si può compilare il codice in qualsiasi momento con script.compile(). Una volta che il codice è compilato, il metodo non ha alcun effetto.
Gli errori nella compilazione del codice e nell'esecuzione sincrona del codice possono essere gestiti con try-catch. Gli errori nell'esecuzione asincrona del codice possono essere gestiti collegando un gestore di eventi uncaughtException al process di 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); });
## Debug di un codice in sandbox
Puoi eseguire il debug o ispezionare il codice in esecuzione nella sandbox come se fosse in esecuzione in un normale processo.
- Puoi usare i punti di interruzione (che richiedono di specificare un nome di file script)
- Puoi usare la parola chiave `debugger`.
- Puoi usare step-in per entrare nel codice in esecuzione nella sandbox.
### Esempio
/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;
## Oggetti di sola lettura (sperimentale)
Per impedire agli script in sandbox di aggiungere, modificare o eliminare proprietà dagli oggetti con proxy, puoi usare i metodi `freeze` per rendere l'oggetto di sola lettura. Questo è efficace solo all'interno della VM. Gli oggetti congelati sono influenzati profondamente. I tipi primitivi non possono essere congelati.
**Esempio senza usare `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
Esempio con l'utilizzo di 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
**IMPORTANTE:** Non è possibile congelare oggetti già esposti tramite proxy alla VM.
## Oggetti protetti (sperimentale)
A differenza di `freeze`, questo metodo consente agli script in sandbox di aggiungere, modificare o eliminare proprietà sugli oggetti, con un'eccezione: non è possibile associare funzioni. Gli script in sandbox non sono quindi in grado di modificare metodi come `toJSON`, `toString` o `inspect`.
**IMPORTANTE:** Non è possibile proteggere oggetti già esposti tramite proxy alla VM.
## Relazioni tra 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);
Prima di poter usare vm2 nella riga di comando, installalo globalmente con npm install vm2 -g.```sh
vm2 ./script.js
## Raccomandazioni di hardening
vm2 previene le fughe dalla sandbox (codice non attendibile che ottiene accesso al reame host). Di per sé **non** previene ogni forma di esaurimento delle risorse o denial-of-service. Gli integratori che eseguono codice non attendibile dovrebbero aggiungere le seguenti difese a strati attorno alla sandbox.
### 1. Limitare l'allocazione di memoria con `bufferAllocLimit`
Una singola chiamata `Buffer.alloc(N)` con `N` controllato dall'attaccante viene eseguita come un'unica allocazione C++ sincrona dell'host che il `timeout` di V8 non può interrompere. In ambienti con memoria limitata, un payload della sandbox di ~100 byte può far aumentare la RSS dell'host di oltre 100 MB e mandare in crash il processo host via OOM. Imposta `bufferAllocLimit` (es. `32 * 1024 * 1024`) per limitare le allocazioni individuali:```js
const vm = new VM({
timeout: 1000,
bufferAllocLimit: 32 * 1024 * 1024,
allowAsync: false,
});
Il tetto si applica anche ai percorsi deprecati Buffer(N) e new Buffer(N). Nota che l'esaurimento aggregato (molte piccole allocazioni, Buffer.concat, Uint8Array, String.repeat, Array(n).fill(), ecc.) non è coperto da questo tetto — combinalo con un limite di memoria lato host (--max-old-space-size, limite del contenitore, cgroup) per una copertura completa.
unhandledRejection lato hostEsiste una classe di DoS da abort del processo host in cui il codice sandbox crea una async function, async function*, o await using il cui corpo lancia un valore che innesca un errore nel reame host durante la formattazione dello stack (ad es. e.name = Symbol(); e.stack). V8 crea la promise di rifiuto tramite la Promise intrinseca del reame, che bypassa il wrapper della sottoclasse Promise di vm2, quindi il rifiuto sfugge all'host come unhandledRejection. Su Node 15+ il comportamento predefinito è terminare il processo.
Chiudere questa falla richiede di modificare il comportamento osservabile dell'host, quindi vm2 non fornisce una correzione di default. Gli integratori dovrebbero installare un gestore a livello di processo che assorba (o registri) i rifiuti provenienti dalla 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); });
Se la tua applicazione non ha altre fonti di rigetti non gestiti, un inghiottimento generale + log è accettabile:```js
process.on('unhandledRejection', reason => {
yourLogger.warn('swallowed sandbox rejection', reason);
});
Una correzione circoscritta potrebbe essere distribuita dietro un flag opt-in swallowSandboxUnhandledRejections in una futura release minore; fino ad allora, il gestore lato host è la mitigazione consigliata.
Anche con bufferAllocLimit impostato, esegui il processo host con --max-old-space-size (o un limite di memoria del container equivalente) dimensionato per il carico di lavoro. Il limite protegge dalla primitiva di allocazione singola; il limite a livello di OS protegge dall'esaurimento aggregato e da qualsiasi futura primitiva di allocazione che vm2 non ha ancora limitato.
require.builtin: ['*'] come una configurazione non-sandboxIl carattere jolly '*' si espande alla maggior parte dei moduli built-in di Node, inclusi child_process, fs, dgram, net, http e dns. Questi sono primitive con piena capacità host — require('child_process').execSync('id') è raggiungibile dalla sandbox con '*'. La semantica di '*' di vm2 è intenzionale (alcuni embedder eseguono codice fidato ma isolato), ma non dovrebbe essere usata come impostazione predefinita per codice non fidato. Preferisci una allowlist esplicita del set più piccolo di moduli di cui la tua sandbox ha realmente bisogno.
nesting: true è una via di fuganesting: true consente al codice della sandbox di fare require('vm2') e costruire NodeVM annidati. La configurazione require della VM annidata è scelta dal codice della sandbox che la costruisce, non vincolata dalla VM esterna. Concretamente:```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);
Se imposti `nesting: true`, hai di fatto concesso alla sandbox lo stesso livello di fiducia che hai tu. **Non abilitare `nesting: true` per codice non affidabile.** Usalo solo quando ti fidi del codice in sandbox ma desideri una semantica di esecuzione in stile VM (global nuovo, timeout controllati) per motivi non legati alla sicurezza.
`nesting: true` **richiede un oggetto di configurazione `require` esplicito** (ad es. `require: { builtin: [] }` o `require: {}`). Qualsiasi altra forma — `require: false`, `require: undefined`, `require: null` o l'omissione completa di `require` — lancia un `VMError` in fase di costruzione (GHSA-m4wx-m65x-ghrr, sostituisce GHSA-8hg8-63c5-gwmx). Tutte queste forme producono un resolver che usa solo NESTING_OVERRIDE: la sandbox può eseguire `require('vm2')` ma nient'altro, il che è una pura primitiva di escape senza alcun uso legittimo. Per negare tutti i require, rimuovi `nesting: true`. Per consentire VM annidate, fornisci una configurazione `require` esplicita così che il compromesso sia visibile nel punto di chiamata.
## Problemi noti
- Non è possibile definire una classe che estende una classe proxy. Questo include l'uso di una classe proxy in `Object.create`.
- L'`eval` diretto non funziona.
- Il log degli array della sandbox ripeterà la parte dell'array nelle proprietà.
- Le trasformazioni del codice sorgente possono produrre una stringa sorgente diversa per una funzione.
- Esistono modi per mandare in crash il processo node dall'interno della sandbox. Vedi [Raccomandazioni di hardening](#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
| Soluzione | Approccio | Prestazioni | Compromessi |
|---|
| isolated-vm | Isolati V8 separati (heap V8 diverso) | Veloce | In modalità di manutenzione; richiede aggiornamenti manuali di V8 |
| Processo separato / Worker | Thread child_process o Worker con permessi limitati | Medio | Maggiore overhead IPC; i dati devono essere serializzati |
| Contenitori / VM | Docker, gVisor, Firecracker | Lento | Overhead di avvio; uso intensivo di risorse |
| Servizi gestiti | Esecuzione di codice basata su cloud (es. AWS Lambda, Cloudflare Workers) | Variabile | Latenza di rete; dipendenza esterna |