mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
esm: protect ESM loader from prototype pollution
Fixes: https://github.com/nodejs/node/issues/45035 PR-URL: https://github.com/nodejs/node/pull/45044 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
eb298dff8d
commit
f2aac0b36b
@ -53,6 +53,7 @@ const {
|
||||
ObjectDefineProperty,
|
||||
ObjectKeys,
|
||||
ObjectPrototypeHasOwnProperty,
|
||||
ObjectSetPrototypeOf,
|
||||
ReflectGet,
|
||||
SafeMap,
|
||||
SafeSet,
|
||||
@ -281,6 +282,8 @@ class BuiltinModule {
|
||||
getESMFacade() {
|
||||
if (this.module) return this.module;
|
||||
const { ModuleWrap } = internalBinding('module_wrap');
|
||||
// TODO(aduh95): move this to C++, alongside the initialization of the class.
|
||||
ObjectSetPrototypeOf(ModuleWrap.prototype, null);
|
||||
const url = `node:${this.id}`;
|
||||
const nativeModule = this;
|
||||
const exportsKeys = ArrayPrototypeSlice(this.exportKeys);
|
||||
|
@ -59,7 +59,7 @@ async function getSource(url, context) {
|
||||
if (policy?.manifest) {
|
||||
policy.manifest.assertIntegrity(parsed, source);
|
||||
}
|
||||
return { responseURL, source };
|
||||
return { __proto__: null, responseURL, source };
|
||||
}
|
||||
|
||||
|
||||
@ -93,6 +93,7 @@ async function defaultLoad(url, context) {
|
||||
}
|
||||
|
||||
return {
|
||||
__proto__: null,
|
||||
format,
|
||||
responseURL,
|
||||
source,
|
||||
|
@ -664,6 +664,7 @@ class ESMLoader {
|
||||
}
|
||||
|
||||
return {
|
||||
__proto__: null,
|
||||
format,
|
||||
responseURL,
|
||||
source,
|
||||
@ -880,6 +881,7 @@ class ESMLoader {
|
||||
}
|
||||
|
||||
return {
|
||||
__proto__: null,
|
||||
format,
|
||||
url,
|
||||
};
|
||||
|
@ -215,7 +215,7 @@ class ModuleJob {
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return { module: this.module };
|
||||
return { __proto__: null, module: this.module };
|
||||
}
|
||||
}
|
||||
ObjectSetPrototypeOf(ModuleJob.prototype, null);
|
||||
|
@ -1017,7 +1017,7 @@ async function defaultResolve(specifier, context = {}) {
|
||||
)
|
||||
)
|
||||
) {
|
||||
return { url: parsed.href };
|
||||
return { __proto__: null, url: parsed.href };
|
||||
}
|
||||
} catch {
|
||||
// Ignore exception
|
||||
|
17
test/es-module/test-cjs-prototype-pollution.js
Normal file
17
test/es-module/test-cjs-prototype-pollution.js
Normal file
@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const { mustNotCall, mustCall } = require('../common');
|
||||
|
||||
Object.defineProperties(Array.prototype, {
|
||||
// %Promise.all% and %Promise.allSettled% are depending on the value of
|
||||
// `%Array.prototype%.then`.
|
||||
then: {},
|
||||
});
|
||||
Object.defineProperties(Object.prototype, {
|
||||
then: {
|
||||
set: mustNotCall('set %Object.prototype%.then'),
|
||||
get: mustNotCall('get %Object.prototype%.then'),
|
||||
},
|
||||
});
|
||||
|
||||
import('data:text/javascript,').then(mustCall());
|
15
test/es-module/test-esm-prototype-pollution.mjs
Normal file
15
test/es-module/test-esm-prototype-pollution.mjs
Normal file
@ -0,0 +1,15 @@
|
||||
import { mustNotCall, mustCall } from '../common/index.mjs';
|
||||
|
||||
Object.defineProperties(Array.prototype, {
|
||||
// %Promise.all% and %Promise.allSettled% are depending on the value of
|
||||
// `%Array.prototype%.then`.
|
||||
then: {},
|
||||
});
|
||||
Object.defineProperties(Object.prototype, {
|
||||
then: {
|
||||
set: mustNotCall('set %Object.prototype%.then'),
|
||||
get: mustNotCall('get %Object.prototype%.then'),
|
||||
},
|
||||
});
|
||||
|
||||
import('data:text/javascript,').then(mustCall());
|
@ -18,9 +18,32 @@ Promise.all = common.mustNotCall('%Promise%.all');
|
||||
Promise.allSettled = common.mustNotCall('%Promise%.allSettled');
|
||||
Promise.any = common.mustNotCall('%Promise%.any');
|
||||
Promise.race = common.mustNotCall('%Promise%.race');
|
||||
Promise.prototype.catch = common.mustNotCall('%Promise.prototype%.catch');
|
||||
Promise.prototype.finally = common.mustNotCall('%Promise.prototype%.finally');
|
||||
Promise.prototype.then = common.mustNotCall('%Promise.prototype%.then');
|
||||
|
||||
Object.defineProperties(Promise.prototype, {
|
||||
catch: {
|
||||
set: common.mustNotCall('set %Promise.prototype%.catch'),
|
||||
get: common.mustNotCall('get %Promise.prototype%.catch'),
|
||||
},
|
||||
finally: {
|
||||
set: common.mustNotCall('set %Promise.prototype%.finally'),
|
||||
get: common.mustNotCall('get %Promise.prototype%.finally'),
|
||||
},
|
||||
then: {
|
||||
set: common.mustNotCall('set %Promise.prototype%.then'),
|
||||
get: common.mustNotCall('get %Promise.prototype%.then'),
|
||||
},
|
||||
});
|
||||
Object.defineProperties(Array.prototype, {
|
||||
// %Promise.all% and %Promise.allSettled% are depending on the value of
|
||||
// `%Array.prototype%.then`.
|
||||
then: {},
|
||||
});
|
||||
Object.defineProperties(Object.prototype, {
|
||||
then: {
|
||||
set: common.mustNotCall('set %Object.prototype%.then'),
|
||||
get: common.mustNotCall('get %Object.prototype%.then'),
|
||||
},
|
||||
});
|
||||
|
||||
assertIsPromise(PromisePrototypeThen(test(), common.mustCall()));
|
||||
assertIsPromise(SafePromisePrototypeFinally(test(), common.mustCall()));
|
||||
|
Loading…
Reference in New Issue
Block a user