/** * Shared prototype-pollution guard for the two dotted-path walkers in this * package: `get`/`set` in `utils/index.ts` and `getAtPath`/`setAtPath` in * `utils/form.ts`. They were written independently and carried the same defect * independently; the guard lives here so a fix to one cannot drift from the * other. * * Two distinct holes are closed, and only the first is obvious: * * 1. A path segment naming `__proto__`, `constructor` or `prototype` writes * through to a shared prototype instead of to the object in hand. * * 2. Walking with `value[key] === undefined` consults the prototype chain, so * an *inherited* member is descended into rather than shadowed — and the * next segment lands on whatever else inherits it. `set({}, 'toString.x', 1)` * assigned to `Object.prototype.toString` with no reserved word anywhere in * the path, which is why a denylist alone is not enough. */ /** * Whether `key` names a prototype-reaching property. * * Compares the *coerced* key, not the key as passed. `object[key]` runs * ToPropertyKey on whatever it is handed, so a guard that first checks * `typeof key === 'string'` inspects a different value than the assignment * that follows it: an array path holding `new String('prototype')`, or any * object whose `toString` returns `'__proto__'`, walked straight past an * earlier version of this check. Symbols are excluded rather than stringified — * `String(Symbol())` throws, and no symbol equals one of these three names. */ export declare function isPrototypeKey(key: unknown): boolean; /** * Throws if any segment of `keys` reaches a prototype. * * Checked up front rather than per step, so a write is refused before it has * half-happened and left intermediate objects behind. * * @throws {TypeError} naming the offending segment. */ export declare function assertNoPrototypeKeys(keys: readonly unknown[], fn: string): void; /** * The container to descend into for `key`, guaranteed to be `object`'s own. * * Assigns one when the slot is empty, and when the value is only inherited * copies it instead of descending into it — replacing it outright would be * safe but would silently drop data the caller can still read through the * prototype chain. The copy preserves array-ness, since a form path like * `items.0.name` depends on it. */ export declare function ownContainer(object: Record, key: string | number, arrayHint?: boolean): Record;