diff --git a/src/theme/provider.tsx b/src/theme/provider.tsx index b4101eaa0f..4da4909183 100644 --- a/src/theme/provider.tsx +++ b/src/theme/provider.tsx @@ -29,6 +29,11 @@ export const isPlatformColorSentinel = (v: unknown): boolean => typeof v === 'object' && ('resource_paths' in v || 'semantic' in v || 'dynamic' in v); +// Keys that would otherwise let a crafted `overrides` object (e.g. parsed via +// `JSON.parse` from an external theme config) hijack the prototype of the +// merged output through bracket-notation assignment below. +const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']); + export const safeMerge = (base: T, overrides: unknown): T => { if ( !base || @@ -45,6 +50,9 @@ export const safeMerge = (base: T, overrides: unknown): T => { } const out: Record = { ...(base as Record) }; for (const key of Object.keys(overrides as Record)) { + if (UNSAFE_KEYS.has(key)) { + continue; + } out[key] = safeMerge( (base as Record)[key], (overrides as Record)[key]