{"record":{"id":"f8e6b42c71eb425e","repo":"solidjs/solid","slug":"refusing-to-set-proto-on-a-store","errorCode":null,"errorMessage":"Refusing to set \"__proto__\" on a store.","messagePattern":"Refusing to set \"__proto__\" on a store\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/solid/store/src/store.ts","lineNumber":235,"sourceCode":"\n  deleteProperty() {\n    if (IS_DEV) console.warn(\"Cannot mutate a Store directly\");\n    return true;\n  },\n\n  ownKeys: ownKeys,\n\n  getOwnPropertyDescriptor: proxyDescriptor\n};\n\nexport function setProperty(\n  state: StoreNode,\n  property: PropertyKey,\n  value: any,\n  deleting: boolean = false\n): void {\n  if (property === \"__proto__\") {\n    if (IS_DEV) console.warn(`Refusing to set \"__proto__\" on a store.`);\n    return;\n  }\n  if (!deleting && state[property] === value) return;\n  const prev = state[property],\n    len = state.length;\n\n  if (IS_DEV)\n    DevHooks.onStoreNodeUpdate && DevHooks.onStoreNodeUpdate(state, property, value, prev);\n\n  if (value === undefined) {\n    delete state[property];\n    if (state[$HAS] && state[$HAS][property] && prev !== undefined) state[$HAS][property].$();\n  } else {\n    state[property] = value;\n    if (state[$HAS] && state[$HAS][property] && prev === undefined) state[$HAS][property].$();\n  }\n  let nodes = getNodes(state, $NODE),\n    node: DataNode | undefined;","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/solidjs/solid/blob/f47845f9cc16ecbb316aa6560c7161f45af9a3d8/packages/solid/store/src/store.ts#L217-L253","documentation":"setProperty, the internal writer used by the store setter, refuses to assign the key __proto__ and warns in dev. Assigning __proto__ on a store node would change the prototype of internal store data, corrupting the Proxy graph and enabling prototype-pollution-style bugs, so Solid no-ops it.","triggerScenarios":"setStore('__proto__', payload), setState with a key computed from user input that equals __proto__, merging unvalidated JSON objects into a store where a __proto__ key survives unwrapping.","commonSituations":"Deep-merge utilities or Object.assign-style merging of API responses into stores; paths built from query params or form field names; migration from lodash.merge into setStore.","solutions":["Sanitize keys before applying: reject __proto__, constructor, prototype","Use setStore(produce(...)) to apply changes programmatically on the draft instead of key-based paths","Validate external objects with a schema (e.g. zod) before merging into stores"],"exampleFix":"// before\nconst patch = JSON.parse(body); // may contain __proto__\nsetStore(k, patch[k]) for all keys; // includes __proto__\n\n// after\nconst safe = JSON.parse(body, (k, v) =>\n  ['__proto__', 'constructor', 'prototype'].includes(k) ? undefined : v\n);\nsetStore(produce(s => Object.assign(s, safe)));","handlingStrategy":"validation","validationCode":"const UNSAFE = new Set(['__proto__', 'constructor', 'prototype']);\nfunction safeAssign(setStore: Function, patch: Record<string, unknown>) {\n  for (const [k, v] of Object.entries(patch)) if (!UNSAFE.has(k)) setStore(k, v);\n}","typeGuard":"const isSafeKey = (k: PropertyKey): boolean =>\n  typeof k === 'symbol' || !['__proto__', 'constructor', 'prototype'].includes(k);","tryCatchPattern":null,"preventionTips":["Reject __proto__/constructor/prototype keys at API boundaries","Use a JSON.parse reviver to strip dangerous keys","Prefer produce for merging untrusted objects"],"tags":["solid","store","prototype-pollution","security","dev-warning"],"backgroundTag":"prototype-pollution-guard","analyzedSha":"f47845f9cc16ecbb316aa6560c7161f45af9a3d8","analyzedAt":"2026-08-27T05:39:24.283Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}