T09 · Insecure Skill Coding Practices
- Location
src/store/sync.ts:8- Finding
Prototype Pollution in Recursive State Merge
- Content
View full analysis
(target: T, source: Partial): T { for (const key of Object.keys(source) as (keyof T)[]) { const sourceValue = source[key]; const targetValue = target[key]; if ( sourceValue !== undefined && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) ) { if (typeof targetValue !== "object" || targetValue === null) { (target as any)[key] = {}; } merge(target[key] as object, sourceValue as object); } else if (sourceValue !== undefined) { (target as any)[key] = sourceValue; } } return target; } ``` The vulnerable function is exposed to synchronized state through: ```typescript export function mergeWithUpdate( localState: T, remoteState: T, ): T { const localUpdateTime = localState.lastUpdateTime ?? 0; const remoteUpdateTime = remoteState.lastUpdateTime ?? 1; if (localUpdateTime < remoteUpdateTime) { merge(remoteState, localState); return { ...remoteState }; } else { merge(localState, remoteState); return { ...localState }; } } ``` ### Technical Analysis The recursive `merge()` function processes every enumerable source key without rejecting special object-property names such as `__proto__`, `prototype`, or `constructor`. When attacker-controlled data parsed from JSON includes a `__proto__` property, accessing `target[key]` can resolve to the target object's inherited prototype. The recursive call can then write attacker-supplied properties into `Object.prototype`. Those properties become visible through inheritance on otherwise unrelated objects througho ...[truncated 1683 chars]- Remediation
View remediation
