From 54461611ec83c3dc1751dbe721792c38354fe2be Mon Sep 17 00:00:00 2001 From: Keichi Takahashi Date: Sun, 18 Oct 2026 23:02:37 +0900 Subject: [PATCH 1/2] Use plain assignment for array hash keys except __proto__ --- lib/binary_parser.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/binary_parser.ts b/lib/binary_parser.ts index 785c62c..d33e03f 100644 --- a/lib/binary_parser.ts +++ b/lib/binary_parser.ts @@ -1356,10 +1356,14 @@ export class Parser { } if (isHash) { - // defineProperty so that keys like "__proto__" become own properties + // Plain assignment is much faster, but "__proto__" would replace the + // prototype, so use defineProperty to make it an own property instead + const hashKey = ctx.generateTmpVariable(); + ctx.pushCode(`var ${hashKey} = ${item}.${key};`); ctx.pushCode( - `Object.defineProperty(${lhs}, ${item}.${key}, { value: ${item}, enumerable: true, writable: true, configurable: true });`, + `if (${hashKey} === "__proto__") Object.defineProperty(${lhs}, ${hashKey}, { value: ${item}, enumerable: true, writable: true, configurable: true });`, ); + ctx.pushCode(`else ${lhs}[${hashKey}] = ${item};`); } else { ctx.pushCode(`${lhs}.push(${item});`); } From d13b033e5c08114f57469ccecda38d317af87b95 Mon Sep 17 00:00:00 2001 From: Keichi Takahashi Date: Sun, 18 Oct 2026 23:04:24 +0900 Subject: [PATCH 2/2] Reject __proto__ keys in associative arrays instead of defining them --- lib/binary_parser.ts | 11 +++++------ test/composite_parser.ts | 12 ++---------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/lib/binary_parser.ts b/lib/binary_parser.ts index d33e03f..8bb9d67 100644 --- a/lib/binary_parser.ts +++ b/lib/binary_parser.ts @@ -1356,14 +1356,13 @@ export class Parser { } if (isHash) { - // Plain assignment is much faster, but "__proto__" would replace the - // prototype, so use defineProperty to make it an own property instead + // Reject "__proto__" since assigning it would replace the prototype const hashKey = ctx.generateTmpVariable(); ctx.pushCode(`var ${hashKey} = ${item}.${key};`); - ctx.pushCode( - `if (${hashKey} === "__proto__") Object.defineProperty(${lhs}, ${hashKey}, { value: ${item}, enumerable: true, writable: true, configurable: true });`, - ); - ctx.pushCode(`else ${lhs}[${hashKey}] = ${item};`); + ctx.pushCode(`if (${hashKey} === "__proto__") {`); + ctx.generateError(`"Invalid key: __proto__"`); + ctx.pushCode("}"); + ctx.pushCode(`${lhs}[${hashKey}] = ${item};`); } else { ctx.pushCode(`${lhs}.push(${item});`); } diff --git a/test/composite_parser.ts b/test/composite_parser.ts index 3f27f49..7c1e591 100644 --- a/test/composite_parser.ts +++ b/test/composite_parser.ts @@ -299,7 +299,7 @@ function compositeParserTests( }, }); }); - it("should store __proto__ key as an own property of associative arrays", () => { + it("should reject __proto__ key of associative arrays", () => { const parser = Parser.start().array("a", { type: Parser.start() .uint8("l") @@ -313,16 +313,8 @@ function compositeParserTests( ...Array.from("__proto__", (c) => c.charCodeAt(0)), 1, ]); - const result = parser.parse(buffer); - expect(Object.keys(result.a)).toStrictEqual(["__proto__"]); - expect(Object.getPrototypeOf(result.a)).toBe(Object.prototype); - expect(result.a.evil).toBeUndefined(); - expect(result.a["__proto__"]).toStrictEqual({ - l: 9, - k: "__proto__", - evil: 1, - }); + expect(() => parser.parse(buffer)).toThrow("Invalid key: __proto__"); }); it("should use formatter to transform parsed array", () => { const parser = Parser.start().array("data", {