From 3742f74aa0bceafc22d61c5177f7693e8a1581b8 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 2 Jan 2023 20:24:52 +0100 Subject: [PATCH 1/2] lib: make `Error` instantiation less vulnerable to prototype pollution --- lib/internal/assert/assertion_error.js | 52 +++++++++------ lib/internal/errors.js | 63 +++++++++--------- lib/internal/event_target.js | 19 ++++-- lib/internal/fs/promises.js | 4 +- lib/internal/http2/util.js | 7 +- lib/internal/main/mksnapshot.js | 3 +- lib/internal/modules/cjs/loader.js | 21 +++--- lib/internal/modules/helpers.js | 2 +- lib/internal/per_context/domexception.js | 8 ++- lib/internal/perf/observe.js | 9 ++- lib/internal/process/promises.js | 9 ++- lib/internal/process/warning.js | 7 +- lib/internal/test_runner/yaml_to_js.js | 3 +- lib/internal/util.js | 18 ------ lib/internal/util/safe-property-assignment.js | 64 +++++++++++++++++++ lib/zlib.js | 4 +- test/parallel/test-bootstrap-modules.js | 1 + 17 files changed, 190 insertions(+), 104 deletions(-) create mode 100644 lib/internal/util/safe-property-assignment.js diff --git a/lib/internal/assert/assertion_error.js b/lib/internal/assert/assertion_error.js index 17e261bd4cb1ef..de0c5917df7399 100644 --- a/lib/internal/assert/assertion_error.js +++ b/lib/internal/assert/assertion_error.js @@ -8,6 +8,7 @@ const { MathMax, ObjectCreate, ObjectDefineProperty, + ObjectDefineProperties, ObjectGetPrototypeOf, ObjectKeys, String, @@ -26,6 +27,7 @@ const { validateObject, } = require('internal/validators'); const { isErrorStackTraceLimitWritable } = require('internal/errors'); +const { assignOwnProperties } = require('internal/util/safe-property-assignment'); const kReadableOperator = { @@ -424,30 +426,42 @@ class AssertionError extends Error { if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit; - this.generatedMessage = !message; - ObjectDefineProperty(this, 'name', { - __proto__: null, - value: 'AssertionError [ERR_ASSERTION]', - enumerable: false, - writable: true, - configurable: true + ObjectDefineProperties(this, { + generatedMessage: { + __proto__: null, + value: !message, + enumerable: true, + writable: true, + configurable: true, + }, + name: { + __proto__: null, + value: 'AssertionError [ERR_ASSERTION]', + enumerable: false, + writable: true, + configurable: true + }, + code: { + __proto__: null, + value: 'ERR_ASSERTION', + enumerable: true, + writable: true, + configurable: true, + }, }); - this.code = 'ERR_ASSERTION'; if (details) { - this.actual = undefined; - this.expected = undefined; - this.operator = undefined; + assignOwnProperties(this, { actual: undefined, expected: undefined, operator: undefined }); for (let i = 0; i < details.length; i++) { - this['message ' + i] = details[i].message; - this['actual ' + i] = details[i].actual; - this['expected ' + i] = details[i].expected; - this['operator ' + i] = details[i].operator; - this['stack trace ' + i] = details[i].stack; + assignOwnProperties(this, { + ['message ' + i]: details[i].message, + ['actual ' + i]: details[i].actual, + ['expected ' + i]: details[i].expected, + ['operator ' + i]: details[i].operator, + ['stack trace ' + i]: details[i].stack, + }); } } else { - this.actual = actual; - this.expected = expected; - this.operator = operator; + assignOwnProperties(this, { actual, expected, operator }); } ErrorCaptureStackTrace(this, stackStartFn || stackStartFunction); // Create error message including the error code in the name. diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 381fa9f15d92f6..4900de7a87a229 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -32,7 +32,7 @@ const { MathMax, Number, NumberIsInteger, - ObjectAssign, + ObjectCreate, ObjectDefineProperty, ObjectDefineProperties, ObjectIsExtensible, @@ -59,12 +59,17 @@ const { URIError, } = primordials; +const { + assignOwnProperties, + setOwnProperty, +} = require('internal/util/safe-property-assignment'); + const kIsNodeError = Symbol('kIsNodeError'); const isWindows = process.platform === 'win32'; const messages = new SafeMap(); -const codes = {}; +const codes = ObjectCreate(null); const classRegExp = /^([A-Z][a-z0-9]*)+$/; // Sorted by a rough estimate on most frequently used entries. @@ -161,7 +166,7 @@ const aggregateTwoErrors = hideStackFrames((innerError, outerError) => { outerError, innerError, ]), outerError.message); - err.code = outerError.code; + setOwnProperty(err, 'code', outerError.code); return err; } return innerError || outerError; @@ -170,7 +175,7 @@ const aggregateTwoErrors = hideStackFrames((innerError, outerError) => { const aggregateErrors = hideStackFrames((errors, message, code) => { // eslint-disable-next-line no-restricted-syntax const err = new AggregateError(new SafeArrayIterator(errors), message); - err.code = errors[0]?.code; + setOwnProperty(err, 'code', errors[0]?.code); return err; }); @@ -249,8 +254,6 @@ class SystemError extends Error { captureLargerStackTrace(this); - this.code = key; - ObjectDefineProperties(this, { [kIsNodeError]: { __proto__: null, @@ -273,6 +276,13 @@ class SystemError extends Error { writable: true, configurable: true, }, + code: { + __proto__: null, + value: key, + enumerable: true, + writable: true, + configurable: true, + }, info: { __proto__: null, value: context, @@ -397,7 +407,7 @@ function makeNodeErrorWithCode(Base, key) { }, }); captureLargerStackTrace(error); - error.code = key; + setOwnProperty(error, 'code', key); return error; }; } @@ -533,15 +543,15 @@ const uvException = hideStackFrames(function uvException(ctx) { if (prop === 'message' || prop === 'path' || prop === 'dest') { continue; } - err[prop] = ctx[prop]; + setOwnProperty(err, prop, ctx[prop]); } - err.code = code; + setOwnProperty(err, 'code', code); if (path) { - err.path = path; + setOwnProperty(err, 'path', path); } if (dest) { - err.dest = dest; + setOwnProperty(err, 'dest', dest); } return captureLargerStackTrace(err); @@ -578,12 +588,9 @@ const uvExceptionWithHostPort = hideStackFrames( // eslint-disable-next-line no-restricted-syntax const ex = new Error(`${message}${details}`); if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit; - ex.code = code; - ex.errno = err; - ex.syscall = syscall; - ex.address = address; + assignOwnProperties(ex, { code, errno: err, syscall, address }); if (port) { - ex.port = port; + setOwnProperty(ex, 'port', port); } return captureLargerStackTrace(ex); @@ -613,9 +620,7 @@ const errnoException = hideStackFrames( // eslint-disable-next-line no-restricted-syntax const ex = new Error(message); if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit; - ex.errno = err; - ex.code = code; - ex.syscall = syscall; + assignOwnProperties(ex, { errno: err, code, syscall }); return captureLargerStackTrace(ex); }); @@ -657,12 +662,9 @@ const exceptionWithHostPort = hideStackFrames( // eslint-disable-next-line no-restricted-syntax const ex = new Error(`${syscall} ${code}${details}`); if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit; - ex.errno = err; - ex.code = code; - ex.syscall = syscall; - ex.address = address; + assignOwnProperties(ex, { errno: err, code, syscall, address }); if (port) { - ex.port = port; + setOwnProperty(ex, 'port', port); } return captureLargerStackTrace(ex); @@ -702,11 +704,9 @@ const dnsException = hideStackFrames(function(code, syscall, hostname) { // eslint-disable-next-line no-restricted-syntax const ex = new Error(message); if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit; - ex.errno = errno; - ex.code = code; - ex.syscall = syscall; + assignOwnProperties(ex, { errno, code, syscall }); if (hostname) { - ex.hostname = hostname; + setOwnProperty(ex, 'hostname', hostname); } return captureLargerStackTrace(ex); @@ -715,7 +715,7 @@ const dnsException = hideStackFrames(function(code, syscall, hostname) { function connResetException(msg) { // eslint-disable-next-line no-restricted-syntax const ex = new Error(msg); - ex.code = 'ECONNRESET'; + setOwnProperty(ex, 'code', 'ECONNRESET'); return ex; } @@ -850,8 +850,7 @@ class AbortError extends Error { throw new codes.ERR_INVALID_ARG_TYPE('options', 'Object', options); } super(message, options); - this.code = 'ABORT_ERR'; - this.name = 'AbortError'; + assignOwnProperties(this, { code: 'ABORT_ERR', name: 'AbortError' }); } } @@ -865,7 +864,7 @@ class AbortError extends Error { const genericNodeError = hideStackFrames(function genericNodeError(message, errorProperties) { // eslint-disable-next-line no-restricted-syntax const err = new Error(message); - ObjectAssign(err, errorProperties); + assignOwnProperties(err, errorProperties); return err; }); diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index ea8ac6652545d9..1f930b22863c08 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -67,6 +67,7 @@ const kIsNodeStyleListener = Symbol('kIsNodeStyleListener'); const kTrustEvent = Symbol('kTrustEvent'); const { now } = require('internal/perf/utils'); +const { assignOwnProperties } = require('internal/util/safe-property-assignment'); const kType = Symbol('type'); const kDetail = Symbol('detail'); @@ -516,10 +517,12 @@ class EventTarget { `${size} ${type} listeners ` + `added to ${inspect(this, { depth: -1 })}. Use ` + 'events.setMaxListeners() to increase limit'); - w.name = 'MaxListenersExceededWarning'; - w.target = this; - w.type = type; - w.count = size; + assignOwnProperties(w, { + name: 'MaxListenersExceededWarning', + target: this, + type, + count: size, + }); process.emitWarning(w); } } @@ -567,9 +570,11 @@ class EventTarget { // eslint-disable-next-line no-restricted-syntax const w = new Error(`addEventListener called with ${listener}` + ' which has no effect.'); - w.name = 'AddEventListenerArgumentTypeWarning'; - w.target = this; - w.type = type; + assignOwnProperties(w, { + name: 'AddEventListenerArgumentTypeWarning', + target: this, + type: type, + }); process.emitWarning(w); return; } diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index 91f90e8b11fe53..f00de8ec5b8dc6 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -108,6 +108,7 @@ const { Interface } = require('internal/readline/interface'); const { JSTransferable, kDeserialize, kTransfer, kTransferList } = require('internal/worker/js_transferable'); +const { assignOwnProperties } = require('internal/util/safe-property-assignment'); const getDirectoryEntriesPromise = promisify(getDirents); const validateRmOptionsPromise = promisify(validateRmOptions); @@ -372,8 +373,7 @@ async function fsCall(fn, handle, ...args) { if (handle.fd === -1) { // eslint-disable-next-line no-restricted-syntax const err = new Error('file closed'); - err.code = 'EBADF'; - err.syscall = fn.name; + assignOwnProperties(err, { code: 'EBADF', syscall: fn.name }); throw err; } diff --git a/lib/internal/http2/util.js b/lib/internal/http2/util.js index ecb943c9b8e37d..aa4cd605bf0b97 100644 --- a/lib/internal/http2/util.js +++ b/lib/internal/http2/util.js @@ -34,6 +34,7 @@ const { hideStackFrames, kIsNodeError, } = require('internal/errors'); +const { assignOwnProperties } = require('internal/util/safe-property-assignment'); const kSensitiveHeaders = Symbol('nodejs.http2.sensitiveHeaders'); const kSocket = Symbol('socket'); @@ -551,8 +552,10 @@ class NghttpError extends Error { super(customErrorCode ? getMessage(customErrorCode, [], null) : binding.nghttp2ErrorString(integerCode)); - this.code = customErrorCode || 'ERR_HTTP2_ERROR'; - this.errno = integerCode; + assignOwnProperties(this, { + code: customErrorCode || 'ERR_HTTP2_ERROR', + errno: integerCode, + }); captureLargerStackTrace(this); ObjectDefineProperty(this, kIsNodeError, { __proto__: null, diff --git a/lib/internal/main/mksnapshot.js b/lib/internal/main/mksnapshot.js index d7ad9324114637..06e9ea001e5e35 100644 --- a/lib/internal/main/mksnapshot.js +++ b/lib/internal/main/mksnapshot.js @@ -22,6 +22,7 @@ const { const { readFileSync } = require('fs'); +const { setOwnProperty } = require('internal/util/safe-property-assignment'); const supportedModules = new SafeSet(new SafeArrayIterator([ // '_http_agent', @@ -100,7 +101,7 @@ function requireForUserSnapshot(id) { const err = new Error( `Cannot find module '${id}'. ` ); - err.code = 'MODULE_NOT_FOUND'; + setOwnProperty(err, 'code', 'MODULE_NOT_FOUND'); throw err; } if (!supportedInUserSnapshot(id)) { diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 092e9545b43563..e5dc87da6da7a8 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -85,9 +85,12 @@ const { emitExperimentalWarning, kEmptyObject, filterOwnProperties, - setOwnProperty, getLazy, } = require('internal/util'); +const { + assignOwnProperties, + setOwnProperty, +} = require('internal/util/safe-property-assignment'); const { internalCompileFunction } = require('internal/vm'); const assert = require('internal/assert'); const fs = require('fs'); @@ -420,9 +423,11 @@ function tryPackage(requestPath, exts, isMain, originalPath) { `Cannot find module '${filename}'. ` + 'Please verify that the package.json has a valid "main" entry' ); - err.code = 'MODULE_NOT_FOUND'; - err.path = path.resolve(requestPath, 'package.json'); - err.requestPath = originalPath; + assignOwnProperties(err, { + code: 'MODULE_NOT_FOUND', + path: path.resolve(requestPath, 'package.json'), + requestPath: originalPath, + }); // TODO(BridgeAR): Add the requireStack as well. throw err; } else { @@ -1059,8 +1064,7 @@ Module._resolveFilename = function(request, parent, isMain, options) { } // eslint-disable-next-line no-restricted-syntax const err = new Error(message); - err.code = 'MODULE_NOT_FOUND'; - err.requireStack = requireStack; + assignOwnProperties(err, { code: 'MODULE_NOT_FOUND', requireStack }); throw err; }; @@ -1081,9 +1085,8 @@ function finalizeEsmResolution(resolved, parentPath, pkgPath) { function createEsmNotFoundErr(request, path) { // eslint-disable-next-line no-restricted-syntax const err = new Error(`Cannot find module '${request}'`); - err.code = 'MODULE_NOT_FOUND'; - if (path) - err.path = path; + setOwnProperty(err, 'code', 'MODULE_NOT_FOUND'); + if (path) setOwnProperty(err, 'path', path); // TODO(BridgeAR): Add the requireStack as well. return err; } diff --git a/lib/internal/modules/helpers.js b/lib/internal/modules/helpers.js index 49c086279e238d..f55a18d94ebf52 100644 --- a/lib/internal/modules/helpers.js +++ b/lib/internal/modules/helpers.js @@ -24,7 +24,7 @@ const path = require('path'); const { pathToFileURL, fileURLToPath, URL } = require('internal/url'); const { getOptionValue } = require('internal/options'); -const { setOwnProperty } = require('internal/util'); +const { setOwnProperty } = require('internal/util/safe-property-assignment'); let debug = require('internal/util/debuglog').debuglog('module', (fn) => { debug = fn; diff --git a/lib/internal/per_context/domexception.js b/lib/internal/per_context/domexception.js index a0814894524a23..0419b568a39b1f 100644 --- a/lib/internal/per_context/domexception.js +++ b/lib/internal/per_context/domexception.js @@ -33,8 +33,14 @@ function throwInvalidThisError(Base, type) { writable: true, configurable: true, }, + code: { + __proto__: null, + value: key, + enumerable: true, + writable: true, + configurable: true, + }, }); - err.code = key; throw err; } diff --git a/lib/internal/perf/observe.js b/lib/internal/perf/observe.js index 9aab2dfbc13ed3..8832b9ff1834bc 100644 --- a/lib/internal/perf/observe.js +++ b/lib/internal/perf/observe.js @@ -71,6 +71,7 @@ const { const { inspect } = require('util'); const { now } = require('internal/perf/utils'); +const { assignOwnProperties } = require('internal/util/safe-property-assignment'); const kBuffer = Symbol('kBuffer'); const kDispatch = Symbol('kDispatch'); @@ -423,9 +424,11 @@ function bufferUserTiming(entry) { 'performance entry buffer. Use ' + `${kClearPerformanceEntryBuffers[entryType]} to ` + 'clear the buffer.'); - w.name = 'MaxPerformanceEntryBufferExceededWarning'; - w.entryType = entryType; - w.count = count; + assignOwnProperties(w, { + name: 'MaxPerformanceEntryBufferExceededWarning', + entryType, + count, + }); process.emitWarning(w); } } diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js index 8d92afd9c29464..0ed60ab12de097 100644 --- a/lib/internal/process/promises.js +++ b/lib/internal/process/promises.js @@ -37,6 +37,7 @@ const { } } = require('internal/async_hooks'); const { isErrorStackTraceLimitWritable } = require('internal/errors'); +const { setOwnProperty, assignOwnProperties } = require('internal/util/safe-property-assignment'); // *Must* match Environment::TickInfo::Fields in src/env.h. const kHasRejectionToWarn = 1; @@ -172,8 +173,10 @@ function handledRejection(promise) { // eslint-disable-next-line no-restricted-syntax const warning = new Error('Promise rejection was handled ' + `asynchronously (rejection id: ${uid})`); - warning.name = 'PromiseRejectionHandledWarning'; - warning.id = uid; + assignOwnProperties(warning, { + name: 'PromiseRejectionHandledWarning', + id: uid, + }); ArrayPrototypePush(asyncHandledRejections, { promise, warning }); setHasRejectionToWarn(true); return; @@ -339,7 +342,7 @@ function generateUnhandledRejectionError(reason) { `"${noSideEffectsToString(reason)}".`; const err = getErrorWithoutStack('UnhandledPromiseRejection', message); - err.code = 'ERR_UNHANDLED_REJECTION'; + setOwnProperty(err, 'code', 'ERR_UNHANDLED_REJECTION'); return err; } diff --git a/lib/internal/process/warning.js b/lib/internal/process/warning.js index 3ce00004dab476..453ddb171b826e 100644 --- a/lib/internal/process/warning.js +++ b/lib/internal/process/warning.js @@ -15,6 +15,7 @@ const { }, isErrorStackTraceLimitWritable, } = require('internal/errors'); +const { setOwnProperty } = require('internal/util/safe-property-assignment'); const { validateString } = require('internal/validators'); // Lazily loaded @@ -179,9 +180,9 @@ function createWarningObject(warning, type, code, ctor, detail) { // eslint-disable-next-line no-restricted-syntax warning = new Error(warning); if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpStackLimit; - warning.name = String(type || 'Warning'); - if (code !== undefined) warning.code = code; - if (detail !== undefined) warning.detail = detail; + setOwnProperty(warning, 'name', String(type || 'Warning')); + if (code !== undefined) setOwnProperty(warning, 'code', code); + if (detail !== undefined) setOwnProperty(warning, 'detail', detail); ErrorCaptureStackTrace(warning, ctor || process.emitWarning); return warning; } diff --git a/lib/internal/test_runner/yaml_to_js.js b/lib/internal/test_runner/yaml_to_js.js index 0642501c275989..c062f9f931a5d2 100644 --- a/lib/internal/test_runner/yaml_to_js.js +++ b/lib/internal/test_runner/yaml_to_js.js @@ -5,6 +5,7 @@ const { } } = require('internal/errors'); const AssertionError = require('internal/assert/assertion_error'); +const { setOwnProperty } = require('internal/util/safe-property-assignment'); const { ArrayPrototypeJoin, ArrayPrototypePush, @@ -42,7 +43,7 @@ function reConstructError(parsedYaml) { } else { // eslint-disable-next-line no-restricted-syntax cause = new Error(parsedYaml.error); - cause.code = parsedYaml.code; + setOwnProperty(cause, 'cause', parsedYaml.code); } cause.stack = stack; diff --git a/lib/internal/util.js b/lib/internal/util.js index 0d769e061fe448..3e5385ab3e3dc8 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -628,23 +628,6 @@ function filterOwnProperties(source, keys) { return filtered; } -/** - * Mimics `obj[key] = value` but ignoring potential prototype inheritance. - * @param {any} obj - * @param {string} key - * @param {any} value - * @returns {any} - */ -function setOwnProperty(obj, key, value) { - return ObjectDefineProperty(obj, key, { - __proto__: null, - configurable: true, - enumerable: true, - value, - writable: true, - }); -} - let internalGlobal; function getInternalGlobal() { if (internalGlobal == null) { @@ -767,5 +750,4 @@ module.exports = { kEmptyObject, kEnumerableProperty, - setOwnProperty, }; diff --git a/lib/internal/util/safe-property-assignment.js b/lib/internal/util/safe-property-assignment.js new file mode 100644 index 00000000000000..1e9c743e4800b2 --- /dev/null +++ b/lib/internal/util/safe-property-assignment.js @@ -0,0 +1,64 @@ +'use strict'; + +const { + ObjectCreate, + ObjectDefineProperties, + ObjectPrototypeHasOwnProperty, + ReflectDefineProperty, + ReflectOwnKeys, +} = primordials; + +/** + * Mimics `obj[key] = value` but ignoring potential prototype inheritance. + * @param {any} obj + * @param {string} key + * @param {any} value + * @returns {boolean} + */ +function setOwnProperty(obj, key, value) { + if (ObjectPrototypeHasOwnProperty(obj, key)) { + obj[key] = value; + return true; + } + return ReflectDefineProperty(obj, key, { + __proto__: null, + configurable: true, + enumerable: true, + value, + writable: true, + }); +} + +/** + * Mimics `Object.assign` but ignoring potential prototype inheritance. + * @template T + * @param {T} obj + * @param {Record[]} sources + * @returns {T} + */ +function assignOwnProperties(obj, ...sources) { + const descriptors = ObjectCreate(null); + for (let i = 0; i < sources.length; i++) { + const keys = ReflectOwnKeys(sources[i]); + for (let j = 0; j < keys.length; j++) { + const key = keys[j]; + if (ObjectPrototypeHasOwnProperty(obj, key)) { + obj[key] = sources[i][key]; + } else { + descriptors[key] = { + __proto__: null, + configurable: true, + enumerable: true, + value: sources[i][key], + writable: true, + }; + } + } + } + return ObjectDefineProperties(obj, descriptors); +} + +module.exports = { + assignOwnProperties, + setOwnProperty, +}; diff --git a/lib/zlib.js b/lib/zlib.js index 9bde1997d95720..48b5076d146482 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -73,6 +73,7 @@ const { validateFunction, validateNumber, } = require('internal/validators'); +const { assignOwnProperties } = require('internal/util/safe-property-assignment'); const kFlushFlag = Symbol('kFlushFlag'); const kError = Symbol('kError'); @@ -187,8 +188,7 @@ function zlibOnError(message, errno, code) { // Continuing only obscures problems. const error = genericNodeError(message, { errno, code }); - error.errno = errno; - error.code = code; + assignOwnProperties(error, { errno, code }); self.destroy(error); self[kError] = error; } diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 693fa9efb4111b..4ec87df4c01f71 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -75,6 +75,7 @@ const expectedModules = new Set([ 'NativeModule internal/util', 'NativeModule internal/util/debuglog', 'NativeModule internal/util/inspect', + 'NativeModule internal/util/safe-property-assignment', 'NativeModule internal/util/types', 'NativeModule internal/v8/startup_snapshot', 'NativeModule internal/validators', From 2e892fcfe9569b2be2a429cf1390ca6d432e2cd3 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 2 Jan 2023 23:48:41 +0100 Subject: [PATCH 2/2] fixup! lib: make `Error` instantiation less vulnerable to prototype pollution --- lib/internal/errors.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 4900de7a87a229..550ec508712afe 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -255,6 +255,13 @@ class SystemError extends Error { captureLargerStackTrace(this); ObjectDefineProperties(this, { + code: { + __proto__: null, + value: key, + enumerable: true, + writable: true, + configurable: true, + }, [kIsNodeError]: { __proto__: null, value: true, @@ -276,13 +283,6 @@ class SystemError extends Error { writable: true, configurable: true, }, - code: { - __proto__: null, - value: key, - enumerable: true, - writable: true, - configurable: true, - }, info: { __proto__: null, value: context,