From 4d74482251deab60e1b523ee43c2640dd6de0140 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:10:18 -0400 Subject: [PATCH 1/4] Preserve __proto__ object keys --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index ea6977d..c75c2a5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -106,7 +106,7 @@ const _parseJSON = (jsonString: string, allow: number) => { index++; // skip colon try { const value = parseAny(); - obj[key] = value; + Object.defineProperty(obj, key, { value, writable: true, enumerable: true, configurable: true }); } catch (e) { if (Allow.OBJ & allow) return obj; else throw e; From 0de0fb8680ee0f9be93e5c69efe510eed19d4cfc Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:10:19 -0400 Subject: [PATCH 2/4] Add __proto__ parsing regression test --- src/proto.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/proto.test.ts diff --git a/src/proto.test.ts b/src/proto.test.ts new file mode 100644 index 0000000..22cf8f5 --- /dev/null +++ b/src/proto.test.ts @@ -0,0 +1,11 @@ +import { describe, expect, it } from "vitest"; +import { parse } from "./index"; + +describe("object key parsing", () => { + it("preserves __proto__ as an own enumerable key", () => { + const value = parse('{"__proto__":0}'); + + expect(value).toEqual({ __proto__: 0 }); + expect(Object.prototype.hasOwnProperty.call(value, "__proto__")).toBe(true); + }); +}); From 419b5a421240a18c6c9181d0fe9917c72ad39c1d Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:10:45 -0400 Subject: [PATCH 3/4] Tighten __proto__ regression assertion --- src/proto.test.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/proto.test.ts b/src/proto.test.ts index 22cf8f5..e33855c 100644 --- a/src/proto.test.ts +++ b/src/proto.test.ts @@ -4,8 +4,13 @@ import { parse } from "./index"; describe("object key parsing", () => { it("preserves __proto__ as an own enumerable key", () => { const value = parse('{"__proto__":0}'); + const descriptor = Object.getOwnPropertyDescriptor(value, "__proto__"); - expect(value).toEqual({ __proto__: 0 }); - expect(Object.prototype.hasOwnProperty.call(value, "__proto__")).toBe(true); + expect(descriptor).toMatchObject({ + value: 0, + writable: true, + enumerable: true, + configurable: true, + }); }); }); From 12f1eb32a704d3d463ea2422f95e80b5f4f14bbf Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:35:10 -0400 Subject: [PATCH 4/4] fix: keep proto defineProperty off normal keys --- src/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index c75c2a5..38e0f9a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -106,7 +106,11 @@ const _parseJSON = (jsonString: string, allow: number) => { index++; // skip colon try { const value = parseAny(); - Object.defineProperty(obj, key, { value, writable: true, enumerable: true, configurable: true }); + if (key === "__proto__") { + Object.defineProperty(obj, key, { value, writable: true, enumerable: true, configurable: true }); + } else { + obj[key] = value; + } } catch (e) { if (Allow.OBJ & allow) return obj; else throw e;