diff --git a/src/Decoder.ts b/src/Decoder.ts index bba8804..5b3c884 100644 --- a/src/Decoder.ts +++ b/src/Decoder.ts @@ -651,8 +651,8 @@ export class Decoder { continue DECODE; } } else if (state.type === STATE_MAP_KEY) { - if (object === "__proto__") { - throw new DecodeError("The key __proto__ is not allowed"); + if (object === "__proto__" || object === "constructor" || object === "prototype") { + throw new DecodeError(`The key ${object} is not allowed`); } state.key = this.mapKeyConverter(object); diff --git a/test/prototype-pollution.test.ts b/test/prototype-pollution.test.ts index 46e293e..29c1b53 100644 --- a/test/prototype-pollution.test.ts +++ b/test/prototype-pollution.test.ts @@ -19,4 +19,40 @@ describe("prototype pollution", () => { }, DecodeError); }); }); + + context("constructor exists as a map key", () => { + it("raises DecodeError in decoding", () => { + const o = { + foo: "bar", + }; + // override constructor as an enumerable property + Object.defineProperty(o, "constructor", { + value: new Date(0), + enumerable: true, + }); + const encoded = encode(o); + + throws(() => { + decode(encoded); + }, DecodeError); + }); + }); + + context("prototype exists as a map key", () => { + it("raises DecodeError in decoding", () => { + const o = { + foo: "bar", + }; + // override prototype as an enumerable property + Object.defineProperty(o, "prototype", { + value: new Date(0), + enumerable: true, + }); + const encoded = encode(o); + + throws(() => { + decode(encoded); + }, DecodeError); + }); + }); });