From 829fe7a338cec08eebc9ccd120e0917bb238e982 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 22 Jun 2023 05:50:05 -0400 Subject: [PATCH 1/2] feat: prevent pollution the Bebop runtime itself was not directly vulnerable, but there is no telling how people will use objects this method revives, so best to bail if we get a hint of maliciousness. also reserves 'prototype', 'constructor' and '__proto__' at the IDL level to prevent misuse --- Core/Meta/BebopSchema.cs | 2 +- Core/Meta/WellKnownTypes.cs | 5 ++++- Laboratory/Schemas/ShouldFail/reserved.bop | 5 +++++ Runtime/TypeScript/index.test.ts | 15 ++++++++++++++- Runtime/TypeScript/index.ts | 3 ++- 5 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 Laboratory/Schemas/ShouldFail/reserved.bop diff --git a/Core/Meta/BebopSchema.cs b/Core/Meta/BebopSchema.cs index 08c3f70e..efcbdd8b 100644 --- a/Core/Meta/BebopSchema.cs +++ b/Core/Meta/BebopSchema.cs @@ -163,7 +163,7 @@ public List Validate() { errors.Add(new MultipleDefinitionsException(definition)); } - if (ReservedWords.Identifiers.Contains(definition.Name)) + if (ReservedWords.Identifiers.Contains(definition.Name, StringComparer.OrdinalIgnoreCase)) { errors.Add(new ReservedIdentifierException(definition.Name, definition.Span)); } diff --git a/Core/Meta/WellKnownTypes.cs b/Core/Meta/WellKnownTypes.cs index ccf2daa5..39dc4476 100644 --- a/Core/Meta/WellKnownTypes.cs +++ b/Core/Meta/WellKnownTypes.cs @@ -21,7 +21,10 @@ public static class ReservedWords "BebopMirror", "BebopConstants", "BopConstants", - "Service" + "Service", + "prototype", + "constructor", + "__proto__" }; } diff --git a/Laboratory/Schemas/ShouldFail/reserved.bop b/Laboratory/Schemas/ShouldFail/reserved.bop new file mode 100644 index 00000000..2db823e2 --- /dev/null +++ b/Laboratory/Schemas/ShouldFail/reserved.bop @@ -0,0 +1,5 @@ +struct BebopRecord { + string prototype; + string constructor; + string __proto__; +} \ No newline at end of file diff --git a/Runtime/TypeScript/index.test.ts b/Runtime/TypeScript/index.test.ts index 8c0356dc..0d87cea6 100644 --- a/Runtime/TypeScript/index.test.ts +++ b/Runtime/TypeScript/index.test.ts @@ -1,4 +1,10 @@ -import { BebopTypeGuard, BebopRuntimeError, BebopJson, GuidMap, Guid } from "./index"; +import { + BebopTypeGuard, + BebopRuntimeError, + BebopJson, + GuidMap, + Guid, +} from "./index"; import { describe, expect, it } from "vitest"; @@ -73,6 +79,13 @@ describe("BebopJson", () => { expect(() => BebopJson.ensureKeysExist(["a.b.c", "e"], obj)).toThrow(); }); }); + + describe("security checks", () => { + it("should not be vulnerable to prototype pollution", () => { + const json = '{"user":{"__proto__":{"admin": true}}}'; + expect(() => JSON.parse(json, BebopJson.reviver)).toThrow(BebopRuntimeError); + }); + }); }); describe("BebopTypeGuard", () => { diff --git a/Runtime/TypeScript/index.ts b/Runtime/TypeScript/index.ts index 05925aff..d01c4e44 100644 --- a/Runtime/TypeScript/index.ts +++ b/Runtime/TypeScript/index.ts @@ -809,8 +809,8 @@ const replacer = (_key: string, value: any): any => { * @returns The modified value for the property, or the original value if not a marked type. */ const reviver = (_key: string, value: any): any => { + if (_key === "__proto__" || _key === "prototype" || _key === "constructor") throw new BebopRuntimeError("potential prototype pollution"); if (_key === "") return value; - if (value && typeof value === "object") { if (value[typeMarker]) { switch (value[typeMarker]) { @@ -846,6 +846,7 @@ const reviver = (_key: string, value: any): any => { } } else { for (let k in value) { + if (k === "__proto__" || k === "prototype" || k === "constructor") throw new BebopRuntimeError("potential prototype pollution"); const v = value[k]; if (!isPrimitive(v)) { value[k] =reviver(k, v); From 12d58ebfb8cf7a9b7d4188b67164835ccd0249fb Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 22 Jun 2023 05:50:43 -0400 Subject: [PATCH 2/2] chore: bump version --- .env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 0ef6c7bb..b9e7e0dd 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -VERSION="2.8.1" +VERSION="2.8.2" MAJOR=2 MINOR=8 -PATCH=1 \ No newline at end of file +PATCH=2 \ No newline at end of file