{"record":{"id":"bf60cda758a63db9","repo":"different-ai/openwork","slug":"property-key-is-not-available-in-codemode","errorCode":null,"errorMessage":"Property '${key}' is not available in CodeMode.","messagePattern":"Property '(.+?)' is not available in CodeMode\\.","errorType":"exception","errorClass":"InterpreterRuntimeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/stdlib/object.ts","lineNumber":19,"sourceCode":"import { type AstNode, InterpreterRuntimeError } from \"../interpreter/model.js\"\nimport { isBlockedMember } from \"../tool-runtime.js\"\nimport { isSandboxValue, SandboxMap, SandboxURLSearchParams } from \"../values.js\"\nimport { boundedData, coerceToString } from \"./value.js\"\n\nexport const objectStatics = new Set([\"keys\", \"values\", \"entries\", \"hasOwn\", \"assign\", \"fromEntries\"])\n\nexport const invokeObjectMethod = (name: string, args: Array<unknown>, node: AstNode): unknown => {\n  if (!objectStatics.has(name)) throw new InterpreterRuntimeError(`Object.${name} is not available in CodeMode.`, node)\n  const requireObject = (): Record<string, unknown> => {\n    const value = boundedData(args[0], `Object.${name} input`)\n    if (isSandboxValue(value)) return {}\n    if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n      throw new InterpreterRuntimeError(`Object.${name} expects a data object.`, node)\n    }\n    return value as Record<string, unknown>\n  }\n  const guardedSet = (out: Record<string, unknown>, key: string, item: unknown): void => {\n    if (isBlockedMember(key)) throw new InterpreterRuntimeError(`Property '${key}' is not available in CodeMode.`, node)\n    out[key] = item\n  }\n  switch (name) {\n    case \"keys\": {\n      const value = boundedData(args[0], \"Object.keys input\")\n      if (isSandboxValue(value)) return []\n      if (Array.isArray(value)) return Object.keys(value)\n      if (value === null || typeof value !== \"object\") {\n        throw new InterpreterRuntimeError(\"Object.keys expects a data object or array.\", node)\n      }\n      return Object.keys(value)\n    }\n    case \"values\":\n      return Object.values(requireObject())\n    case \"entries\":\n      return Object.entries(requireObject()).map(([key, item]) => [key, item])\n    case \"hasOwn\":\n      return Object.hasOwn(requireObject(), String(args[1]))","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/stdlib/object.ts#L1-L37","documentation":"guardedSet is used by Object.assign and Object.fromEntries in CodeMode to block writing properties whose keys match isBlockedMember (a denylist of dangerous names like __proto__, constructor, prototype). Writing such a key throws this error to prevent prototype-pollution-style attacks inside the sandbox.","triggerScenarios":"Object.assign(target, {__proto__: x}), Object.fromEntries([['__proto__', {}]]), Object.fromEntries([['constructor', fn]]), or merging user/API-supplied key/value data that contains keys named __proto__, prototype, or constructor.","commonSituations":"Merging untrusted API/JSON payloads into config objects where a payload key collides with a blocked name; CSV/JSON ingest where a column is literally named __proto__.","solutions":["Sanitize input keys before calling assign/fromEntries: drop or rename keys matching /^( __proto__|constructor|prototype)$/","Use a prefix or namespaced keys for untrusted data, e.g. store as meta['field'] instead of raw keys","Filter pairs: pairs.filter(([k]) => k !== '__proto__' && k !== 'constructor' && k !== 'prototype')","If the key is legitimately needed, transform it (e.g. underscore prefix) before constructing the object"],"exampleFix":"// before\nconst merged = Object.assign({}, userInput)\n// after\nconst safe = Object.fromEntries(\n  Object.entries(userInput).filter(([k]) => !['__proto__','constructor','prototype'].includes(k))\n)\nconst merged = Object.assign({}, safe)","handlingStrategy":"validation","validationCode":"const BLOCKED = new Set(['__proto__','constructor','prototype'])\nconst sanitized = Object.fromEntries(\n  pairs.filter(([k]) => !BLOCKED.has(String(k)))\n)","typeGuard":null,"tryCatchPattern":"try {\n  return Object.assign({}, untrusted)\n} catch (e) {\n  if (e instanceof InterpreterRuntimeError && e.message.includes(\"is not available in CodeMode\") && e.message.includes(\"Property\")) {\n    return Object.assign({}, filterBlockedKeys(untrusted))\n  }\n  throw e\n}","preventionTips":["Filter __proto__/constructor/prototype keys from any untrusted input","Namespace untrusted payload keys before merging","Never merge raw user/API key-value data blindly","Fuzz your merge paths with payloads containing dangerous keys"],"tags":["codemode","security","prototype-pollution","object"],"backgroundTag":"prototype-pollution-blocked","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}