From 852043f9621f098ccf3a577a1d9a2ed0de20f402 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Mon, 12 Jul 2021 14:04:51 -0700 Subject: [PATCH] Use `vm2` module to prevent privilege escalation of untrusted code (#11) --- package.json | 3 ++- src/index.ts | 10 ++++------ test/test.ts | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 0d85ada..b583a63 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "dependencies": { "ast-types": "^0.13.2", "escodegen": "^1.8.1", - "esprima": "^4.0.0" + "esprima": "^4.0.0", + "vm2": "^3.9.3" }, "devDependencies": { "@types/escodegen": "^0.0.6", diff --git a/src/index.ts b/src/index.ts index 162399a..b8d40d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,8 @@ import { isRegExp } from 'util'; import { generate } from 'escodegen'; import { parseScript } from 'esprima'; import { visit, namedTypes as n, builders as b } from 'ast-types'; -import { Context, RunningScriptOptions, runInNewContext } from 'vm'; +import { Context, RunningScriptOptions } from 'vm'; +import { VM } from 'vm2'; /** * Compiles sync JavaScript code into JavaScript with async Functions. @@ -136,11 +137,8 @@ namespace degenerator { options: CompileOptions = {} ): (...args: A) => Promise { const compiled = degenerator(code, names); - const fn = runInNewContext( - `${compiled};${returnName}`, - options.sandbox, - options - ); + const vm = new VM(options); + const fn = vm.run(`${compiled};${returnName}`); if (typeof fn !== 'function') { throw new Error( `Expected a "function" to be returned for \`${returnName}\`, but got "${typeof fn}"` diff --git a/test/test.ts b/test/test.ts index fefee6f..2fb9b87 100644 --- a/test/test.ts +++ b/test/test.ts @@ -159,5 +159,19 @@ describe('degenerator()', () => { assert.equal(val, 'foo'); }); }); + it('should prevent privilege escalation of untrusted code', async() => { + let err; + try { + const fn = compile( + `const f = this.constructor.constructor('return process');`, + 'f', + [], + ); + await fn(); + } catch(_err) { + err = _err; + } + assert.equal(err.message,'process is not defined') + }); }); });