Skip to content

Commit f23b2a3

Browse files
aduh95RafaelGSS
authored andcommitted
esm: protect ERR_UNSUPPORTED_DIR_IMPORT against prototype pollution
PR-URL: #49060 Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Jacob Smith <jacob@frende.me>
1 parent 669ac03 commit f23b2a3

File tree

3 files changed

+24
-25
lines changed

3 files changed

+24
-25
lines changed

lib/internal/errors.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -1696,8 +1696,11 @@ E('ERR_UNKNOWN_FILE_EXTENSION', (ext, path, suggestion) => {
16961696
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s for URL %s',
16971697
RangeError);
16981698
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError);
1699-
E('ERR_UNSUPPORTED_DIR_IMPORT', "Directory import '%s' is not supported " +
1700-
'resolving ES modules imported from %s', Error);
1699+
E('ERR_UNSUPPORTED_DIR_IMPORT', function(path, base, exactUrl) {
1700+
lazyInternalUtil().setOwnProperty(this, 'url', exactUrl);
1701+
return `Directory import '${path}' is not supported ` +
1702+
`resolving ES modules imported from ${base}`;
1703+
}, Error);
17011704
E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url, supported) => {
17021705
let msg = `Only URLs with a scheme in: ${formatList(supported)} are supported by the default ESM loader`;
17031706
if (isWindows && url.protocol.length === 2) {

lib/internal/modules/esm/resolve.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,7 @@ function finalizeResolution(resolved, base, preserveSymlinks) {
215215

216216
// Check for stats.isDirectory()
217217
if (stats === 1) {
218-
const err = new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base));
219-
err.url = String(resolved);
220-
throw err;
218+
throw new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base), String(resolved));
221219
} else if (stats !== 0) {
222220
// Check for !stats.isFile()
223221
if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) {
+18-20
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
1-
import '../common/index.mjs';
1+
import { mustNotCall } from '../common/index.mjs';
2+
import * as fixtures from '../common/fixtures.mjs';
23
import assert from 'assert';
34

4-
async function main() {
5-
let mod;
6-
try {
7-
mod = await import('../fixtures/es-modules/pjson-main');
8-
} catch (e) {
9-
assert.strictEqual(e.code, 'ERR_UNSUPPORTED_DIR_IMPORT');
10-
}
5+
Object.defineProperty(Error.prototype, 'url', {
6+
get: mustNotCall('get %Error.prototype%.url'),
7+
set: mustNotCall('set %Error.prototype%.url'),
8+
});
9+
Object.defineProperty(Object.prototype, 'url', {
10+
get: mustNotCall('get %Object.prototype%.url'),
11+
set: mustNotCall('set %Object.prototype%.url'),
12+
});
1113

12-
assert.strictEqual(mod, undefined);
14+
await assert.rejects(import('../fixtures/es-modules/pjson-main'), {
15+
code: 'ERR_UNSUPPORTED_DIR_IMPORT',
16+
url: fixtures.fileURL('es-modules/pjson-main').href,
17+
});
1318

14-
try {
15-
mod = await import('../fixtures/es-modules/pjson-main/main.mjs');
16-
} catch (e) {
17-
console.log(e);
18-
assert.fail();
19-
}
20-
21-
assert.strictEqual(mod.main, 'main');
22-
}
23-
24-
main();
19+
assert.deepStrictEqual(
20+
{ ...await import('../fixtures/es-modules/pjson-main/main.mjs') },
21+
{ main: 'main' },
22+
);

0 commit comments

Comments
 (0)