Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3e17a8e

Browse filesBrowse files
committed
util: harden more built-in classes against prototype pollution
PR-URL: #56225 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
1 parent 25bb462 commit 3e17a8e
Copy full SHA for 3e17a8e

File tree

Expand file treeCollapse file tree

3 files changed

+67
-4
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+67
-4
lines changed
Open diff view settings
Collapse file

‎lib/buffer.js‎

Copy file name to clipboardExpand all lines: lib/buffer.js
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const {
3535
NumberMIN_SAFE_INTEGER,
3636
ObjectDefineProperties,
3737
ObjectDefineProperty,
38+
ObjectPrototypeHasOwnProperty,
3839
ObjectSetPrototypeOf,
3940
RegExpPrototypeSymbolReplace,
4041
StringPrototypeCharCodeAt,
@@ -910,7 +911,14 @@ Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) {
910911
}), 27, -2);
911912
}
912913
}
913-
return `<${this.constructor.name} ${str}>`;
914+
let constructorName = 'Buffer';
915+
try {
916+
const { constructor } = this;
917+
if (typeof constructor === 'function' && ObjectPrototypeHasOwnProperty(constructor, 'name')) {
918+
constructorName = constructor.name;
919+
}
920+
} catch { /* Ignore error and use default name */ }
921+
return `<${constructorName} ${str}>`;
914922
};
915923
Buffer.prototype.inspect = Buffer.prototype[customInspectSymbol];
916924

Collapse file

‎lib/internal/util/inspect.js‎

Copy file name to clipboardExpand all lines: lib/internal/util/inspect.js
+17-3Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
const {
44
Array,
5+
ArrayBuffer,
6+
ArrayBufferPrototype,
57
ArrayIsArray,
8+
ArrayPrototype,
69
ArrayPrototypeFilter,
710
ArrayPrototypeForEach,
811
ArrayPrototypeIncludes,
@@ -29,6 +32,8 @@ const {
2932
FunctionPrototypeSymbolHasInstance,
3033
FunctionPrototypeToString,
3134
JSONStringify,
35+
Map,
36+
MapPrototype,
3237
MapPrototypeEntries,
3338
MapPrototypeGetSize,
3439
MathFloor,
@@ -68,6 +73,8 @@ const {
6873
SafeMap,
6974
SafeSet,
7075
SafeStringIterator,
76+
Set,
77+
SetPrototype,
7178
SetPrototypeGetSize,
7279
SetPrototypeValues,
7380
String,
@@ -93,6 +100,8 @@ const {
93100
SymbolPrototypeValueOf,
94101
SymbolToPrimitive,
95102
SymbolToStringTag,
103+
TypedArray,
104+
TypedArrayPrototype,
96105
TypedArrayPrototypeGetLength,
97106
TypedArrayPrototypeGetSymbolToStringTag,
98107
Uint8Array,
@@ -599,8 +608,13 @@ function isInstanceof(object, proto) {
599608

600609
// Special-case for some builtin prototypes in case their `constructor` property has been tampered.
601610
const wellKnownPrototypes = new SafeMap();
602-
wellKnownPrototypes.set(ObjectPrototype, { name: 'Object', constructor: Object });
611+
wellKnownPrototypes.set(ArrayPrototype, { name: 'Array', constructor: Array });
612+
wellKnownPrototypes.set(ArrayBufferPrototype, { name: 'ArrayBuffer', constructor: ArrayBuffer });
603613
wellKnownPrototypes.set(FunctionPrototype, { name: 'Function', constructor: Function });
614+
wellKnownPrototypes.set(MapPrototype, { name: 'Map', constructor: Map });
615+
wellKnownPrototypes.set(ObjectPrototype, { name: 'Object', constructor: Object });
616+
wellKnownPrototypes.set(SetPrototype, { name: 'Set', constructor: Set });
617+
wellKnownPrototypes.set(TypedArrayPrototype, { name: 'TypedArray', constructor: TypedArray });
604618

605619
function getConstructorName(obj, ctx, recurseTimes, protoProps) {
606620
let firstProto;
@@ -825,12 +839,12 @@ function formatValue(ctx, value, recurseTimes, typedArray) {
825839
// Filter out the util module, its inspect function is special.
826840
maybeCustom !== inspect &&
827841
// Also filter out any prototype objects using the circular check.
828-
!(value.constructor && value.constructor.prototype === value)) {
842+
ObjectGetOwnPropertyDescriptor(value, 'constructor')?.value?.prototype !== value) {
829843
// This makes sure the recurseTimes are reported as before while using
830844
// a counter internally.
831845
const depth = ctx.depth === null ? null : ctx.depth - recurseTimes;
832846
const isCrossContext =
833-
proxy !== undefined || !(context instanceof Object);
847+
proxy !== undefined || !FunctionPrototypeSymbolHasInstance(Object, context);
834848
const ret = FunctionPrototypeCall(
835849
maybeCustom,
836850
context,
Collapse file

‎test/parallel/test-util-inspect.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-util-inspect.js
+41Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3353,3 +3353,44 @@ assert.strictEqual(
33533353
);
33543354
Object.defineProperty(BuiltinPrototype, 'constructor', desc);
33553355
}
3356+
{
3357+
const prototypes = [
3358+
Array.prototype,
3359+
ArrayBuffer.prototype,
3360+
Buffer.prototype,
3361+
Function.prototype,
3362+
Map.prototype,
3363+
Object.prototype,
3364+
Reflect.getPrototypeOf(Uint8Array.prototype),
3365+
Set.prototype,
3366+
Uint8Array.prototype,
3367+
];
3368+
const descriptors = new Map();
3369+
const buffer = Buffer.from('Hello');
3370+
const o = {
3371+
arrayBuffer: new ArrayBuffer(), buffer, typedArray: Uint8Array.from(buffer),
3372+
array: [], func() {}, set: new Set([1]), map: new Map(),
3373+
};
3374+
for (const BuiltinPrototype of prototypes) {
3375+
descriptors.set(BuiltinPrototype, Reflect.getOwnPropertyDescriptor(BuiltinPrototype, 'constructor'));
3376+
Object.defineProperty(BuiltinPrototype, 'constructor', {
3377+
get: () => BuiltinPrototype,
3378+
configurable: true,
3379+
});
3380+
}
3381+
assert.strictEqual(
3382+
util.inspect(o),
3383+
'{\n' +
3384+
' arrayBuffer: ArrayBuffer { [Uint8Contents]: <>, byteLength: 0 },\n' +
3385+
' buffer: <Buffer 48 65 6c 6c 6f>,\n' +
3386+
' typedArray: TypedArray(5) [Uint8Array] [ 72, 101, 108, 108, 111 ],\n' +
3387+
' array: [],\n' +
3388+
' func: [Function: func],\n' +
3389+
' set: Set(1) { 1 },\n' +
3390+
' map: Map(0) {}\n' +
3391+
'}',
3392+
);
3393+
for (const [BuiltinPrototype, desc] of descriptors) {
3394+
Object.defineProperty(BuiltinPrototype, 'constructor', desc);
3395+
}
3396+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.