{"record":{"id":"5c6d7cb714b9a1bb","repo":"nanocoai/nanoclaw","slug":"stdin-json-key-proto-is-not-allowed-5c6d7c","errorCode":null,"errorMessage":"--stdin-json key \"__proto__\" is not allowed","messagePattern":"--stdin-json key \"__proto__\" is not allowed","errorType":"validation","errorClass":"StdinJsonInputError","httpStatus":null,"severity":"error","filePath":"src/cli/stdin-json.ts","lineNumber":112,"sourceCode":" * is stdin-vs-argv or two stdin keys.\n *\n * `__proto__` is rejected outright as a prototype-pollution guard: parsed\n * args flow into downstream handlers that copy them by plain assignment.\n */\nfunction assertNoKeyConflicts(\n  stdinArgs: Readonly<Record<string, unknown>>,\n  argvArgs: Readonly<Record<string, unknown>>,\n): void {\n  const argvKeysByCanonical = new Map<string, string>();\n  for (const key of Object.keys(argvArgs)) {\n    const canonical = canonicalArgKey(key);\n    if (!argvKeysByCanonical.has(canonical)) argvKeysByCanonical.set(canonical, key);\n  }\n\n  const stdinKeysByCanonical = new Map<string, string>();\n  for (const key of Object.keys(stdinArgs)) {\n    if (key === '__proto__') {\n      throw new StdinJsonInputError('--stdin-json key \"__proto__\" is not allowed');\n    }\n\n    if (Object.prototype.hasOwnProperty.call(argvArgs, key)) {\n      throw new StdinJsonInputError(`--stdin-json key \"${key}\" is also supplied on argv`);\n    }\n\n    const canonical = canonicalArgKey(key);\n    const argvKey = argvKeysByCanonical.get(canonical);\n    if (argvKey !== undefined) {\n      throw new StdinJsonInputError(\n        `--stdin-json key \"${key}\" conflicts with argv key \"${argvKey}\" after CLI key normalization`,\n      );\n    }\n\n    const priorStdinKey = stdinKeysByCanonical.get(canonical);\n    if (priorStdinKey !== undefined) {\n      throw new StdinJsonInputError(\n        `--stdin-json keys \"${priorStdinKey}\" and \"${key}\" conflict after CLI key normalization`,","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/cli/stdin-json.ts#L94-L130","documentation":"assertNoKeyConflicts rejects the key \"__proto__\" in --stdin-json input. Assigning it would set the merged args object's prototype instead of an own key, a prototype-pollution vector, so it is rejected outright.","triggerScenarios":"Passing {\"__proto__\": {...}} in the stdin JSON — usually a test of the guard or a crafted payload.","commonSituations":"Security testing, or accidentally merging an object whose prototype was serialized.","solutions":["Remove the __proto__ key from the input","Use only plain argument keys"],"exampleFix":"# before\necho '{\"__proto__\": {}, \"name\": \"x\"}' | ncl groups create --stdin-json\n# after\necho '{\"name\": \"x\"}' | ncl groups create --stdin-json","handlingStrategy":"validation","validationCode":"if (Object.prototype.hasOwnProperty.call(args, '__proto__')) throw new Error('rejected');\n// safer parse: JSON.parse yields own keys only","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never accept untrusted JSON merged with Object.assign; use JSON.parse"],"tags":["cli","stdin-json","security","prototype-pollution"],"backgroundTag":"prototype-pollution","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}