diff --git a/lib/binary_parser.ts b/lib/binary_parser.ts index cf511f6..0335f71 100644 --- a/lib/binary_parser.ts +++ b/lib/binary_parser.ts @@ -1353,7 +1353,10 @@ export class Parser { } if (isHash) { - ctx.pushCode(`${lhs}[${item}.${key}] = ${item};`); + // defineProperty so that keys like "__proto__" become own properties + ctx.pushCode( + `Object.defineProperty(${lhs}, ${item}.${key}, { value: ${item}, enumerable: true, writable: true, configurable: true });`, + ); } else { ctx.pushCode(`${lhs}.push(${item});`); } diff --git a/test/composite_parser.ts b/test/composite_parser.ts index b369b54..319b6ff 100644 --- a/test/composite_parser.ts +++ b/test/composite_parser.ts @@ -287,6 +287,31 @@ function compositeParserTests( }, }); }); + it("should store __proto__ key as an own property of associative arrays", () => { + const parser = Parser.start().array("a", { + type: Parser.start() + .uint8("l") + .string("k", { length: "l" }) + .uint8("evil"), + lengthInBytes: 11, + key: "k", + }); + const buffer = factory([ + 9, + ...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, + }); + }); it("should use formatter to transform parsed array", () => { const parser = Parser.start().array("data", { type: "uint8",