CVE-2021-23406: Insufficient Information (NVD-CWE-noinfo)
value: This affects the package pac-resolver before 5.0.0. This can occur when used with untrusted input, due to unsafe PAC file handling. **NOTE:** The fix for this vulnerability is applied in the node-degenerator library, a dependency written by the same maintainer.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 9.8
Published: 2021-08-24T08:15Z
Repository: https://github.com/TooTallNate/node-degenerator
Language: TypeScript
Files changed: src/index.ts, test/test.ts
Commit date: 2021-07-12 14:27:04 -0700
Commit message: Fix `filename` option

Diff: diff --git a/src/index.ts b/src/index.ts
index 9f5c83f..fcafafb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,11 +1,11 @@
 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 } from 'vm';
-import { VM } from 'vm2';
+import { VM, VMScript } from 'vm2';
 
 /**
  * Compiles sync JavaScript code into JavaScript with async Functions.
  *
  * @param {String} code JavaScript string to convert
@@ -136,11 +136,14 @@ namespace degenerator {
 		names: DegeneratorNames,
 		options: CompileOptions = {}
 	): (...args: A) => Promise<R> {
 		const compiled = degenerator(code, names);
 		const vm = new VM(options);
-		const fn = vm.run(`${compiled};${returnName}`);
+		const script = new VMScript(`${compiled};${returnName}`, {
+			filename: options.filename,
+		});
+		const fn = vm.run(script);
 		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 e42fa72..e36a82a 100644
--- a/test/test.ts
+++ b/test/test.ts
@@ -157,28 +157,44 @@ describe('degenerator()', () => {
 			});
 			return fn().then((val: string) => {
 				assert.equal(val, 'foo');
 			});
 		});
-		it('should prevent privilege escalation of untrusted code', async() => {
+		it('should prevent privilege escalation of untrusted code', async () => {
 			let err;
 			try {
 				const fn = compile<typeof process>(
 					`const f = this.constructor.constructor('return process');`,
 					'f',
-					[],
+					[]
 				);
 				await fn();
-			} catch(_err) {
+			} catch (_err) {
 				err = _err;
 			}
-			assert.equal(err.message,'process is not defined')
+			assert.equal(err.message, 'process is not defined');
 		});
 		it('should allow to return synchronous undefined', () => {
 			function u() {}
 			const fn = compile(`${u}`, 'u', ['']);
-			return fn().then(val => {
+			return fn().then((val) => {
 				assert.strictEqual(val, undefined);
 			});
 		});
+		it('should support "filename" option', async () => {
+			function u() {
+				throw new Error('fail');
+			}
+			let err;
+			const fn = compile(`${u}`, 'u', [''], {
+				filename: '/foo/bar/baz.js',
+			});
+			try {
+				await fn();
+			} catch (_err) {
+				err = _err;
+			}
+			assert.strictEqual(err.message, 'fail');
+			assert(err.stack.includes('at u (/foo/bar/baz.js:'));
+		});
 	});
 });

Vulnerable code: import { VM } from 'vm2';
		const fn = vm.run(`${compiled};${returnName}`);
		it('should prevent privilege escalation of untrusted code', async() => {
					[],
			} catch(_err) {
			assert.equal(err.message,'process is not defined')
			return fn().then(val => {
Fixed code: import { VM, VMScript } from 'vm2';
		const script = new VMScript(`${compiled};${returnName}`, {
			filename: options.filename,
		});
		const fn = vm.run(script);
		it('should prevent privilege escalation of untrusted code', async () => {
					[]
			} catch (_err) {
			assert.equal(err.message, 'process is not defined');
			return fn().then((val) => {
		it('should support "filename" option', async () => {
			function u() {
				throw new Error('fail');
			}
			let err;
			const fn = compile(`${u}`, 'u', [''], {
				filename: '/foo/bar/baz.js',
			});
			try {
				await fn();
			} catch (_err) {
				err = _err;
			}
			assert.strictEqual(err.message, 'fail');
			assert(err.stack.includes('at u (/foo/bar/baz.js:'));
		});