solidjs/solid · warning

Refusing to traverse unsafe key "${part}" on a store.

Error message

Refusing to traverse unsafe key "${part}" on a store.

What it means

updatePath, which walks setter paths like setStore('a', 'b', value), refuses to traverse __proto__ (always) and other unsafe keys (constructor/prototype-style keys when further path segments follow), warning in dev. Traversing such keys would walk up the prototype chain and write outside the store's own data, a prototype-pollution vector.

Source

Thrown at packages/solid/store/src/store.ts:303

      len = next.length;
    for (; i < len; i++) {
      const value = next[i];
      if (current[i] !== value) setProperty(current, i, value);
    }
    setProperty(current, "length", len);
  } else mergeStoreNode(current, next);
}

export function updatePath(current: StoreNode, path: any[], traversed: PropertyKey[] = []) {
  let part,
    prev = current;
  if (path.length > 1) {
    part = path.shift();
    const partType = typeof part,
      isArray = Array.isArray(current);

    if (partType === "string" && (part === "__proto__" || (path.length > 1 && isUnsafeKey(part)))) {
      if (IS_DEV) console.warn(`Refusing to traverse unsafe key "${part}" on a store.`);
      return;
    }

    if (Array.isArray(part)) {
      // Ex. update('data', [2, 23], 'label', l => l + ' !!!');
      for (let i = 0; i < part.length; i++) {
        updatePath(current, [part[i]].concat(path), traversed);
      }
      return;
    } else if (isArray && partType === "function") {
      // Ex. update('data', i => i.id === 42, 'label', l => l + ' !!!');
      for (let i = 0; i < current.length; i++) {
        if (part(current[i], i)) updatePath(current, [i].concat(path), traversed);
      }
      return;
    } else if (isArray && partType === "object") {
      // Ex. update('data', { from: 3, to: 12, by: 2 }, 'label', l => l + ' !!!');
      const { from = 0, to = current.length - 1, by = 1 } = part;

View on GitHub (pinned to f47845f9cc)

Solutions

  1. Validate path segments against /^[A-Za-z0-9_$-]+$/ or a whitelist before calling setStore
  2. Block __proto__/constructor/prototype keys at the API boundary
  3. Use produce for deep programmatic edits rather than dynamic key paths

Example fix

// before
function deepSet(store, path, value) {
  setStore(...path.split('.'), value); // 'a.__proto__.x' traverses
}

// after
const UNSAFE = ['__proto__', 'constructor', 'prototype'];
function deepSet(setStore, path, value) {
  const parts = path.split('.');
  if (parts.some(p => UNSAFE.includes(p))) throw new Error('unsafe path');
  setStore(...parts, value);
}
Defensive patterns

Strategy: validation

Validate before calling

const UNSAFE = ['__proto__', 'constructor', 'prototype'];
function deepSet(setStore: Function, pathStr: string, value: unknown) {
  const parts = pathStr.split('.');
  if (parts.some(p => !p.length || UNSAFE.includes(p))) throw new Error('unsafe store path');
  setStore(...parts, value);
}

Type guard

const isSafePath = (parts: string[]): boolean =>
  parts.every(p => /^[A-Za-z0-9_$-]+$/.test(p) && !['__proto__', 'constructor', 'prototype'].includes(p));

Prevention

When it happens

Trigger: setStore('__proto__', 'polluted', true); setStore('constructor', 'prototype', x); or building a path array from unvalidated user input (dot-split body keys like user-provided 'a.__proto__.b').

Common situations: Generic deep-set helpers that split key strings on dots and forward to setStore; accepting nested updates from APIs/websockets; porting MongoDB-style update operators into store updates.

Related errors


AI-assisted analysis of solidjs/solid@f47845f9cc (2026-08-27). Data as JSON: /api/errors/bcebd86fefa28945. Report an issue: GitHub.