{"record":{"id":"cf2e2a8eed42e663","repo":"toeverything/AFFiNE","slug":"invalid-rowid","errorCode":null,"errorMessage":"Invalid rowId","messagePattern":"Invalid rowId","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"blocksuite/affine/blocks/database/src/utils/block-utils.ts","lineNumber":190,"sourceCode":"        value: cell.value,\n      };\n    }\n  });\n}\n\nexport function updateCells(\n  model: DatabaseBlockModel,\n  columnId: string,\n  cells: Record<string, unknown>\n) {\n  model.store.transact(() => {\n    Object.entries(cells).forEach(([rowId, value]) => {\n      if (\n        rowId === '__proto__' ||\n        rowId === 'constructor' ||\n        rowId === 'prototype'\n      ) {\n        throw new Error('Invalid rowId');\n      }\n      if (!model.props.cells[rowId]) {\n        model.props.cells[rowId] = Object.create(null);\n      }\n      if (model.props.cells[rowId]) {\n        model.props.cells[rowId][columnId] = {\n          columnId,\n          value,\n        };\n      }\n    });\n  });\n}\n\nexport function updateProperty(\n  model: DatabaseBlockModel,\n  id: string,\n  updater: ColumnUpdater,","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/blocksuite/affine/blocks/database/src/utils/block-utils.ts#L172-L208","documentation":"updateCells guards the cells map (model.props.cells) against prototype-pollution by rejecting the keys '__proto__', 'constructor', and 'prototype'. These keys, if written into a plain object used as a map, can poison Object/prototype in JS engines. The guard is a hard stop: no fallback, the transaction still runs but the throw propagates.","triggerScenarios":"Calling updateCells(model, columnId, cells) where cells has a key equal to '__proto__', 'constructor', or 'prototype'. This typically arises from untrusted/parsed input (JSON.parse of remote data, snapshot imports, copy-paste payloads, or CSV import where a row header is one of these strings).","commonSituations":"Importing external data (CSV/JSON) whose row identifiers collide with built-in object property names; deserializing a snapshot that an attacker or buggy exporter crafted; feeding user-typed row ids straight into updateCells without sanitisation.","solutions":["Sanitise row ids before calling updateCells: reject or rename keys in {'__proto__','constructor','prototype'} (and ideally any non-string or empty key).","Construct model.props.cells with Object.create(null) (the function already does per-row) but also keep the input record null-prototype to avoid accidental pollution upstream.","Validate external payloads against a row-id schema before they reach the database block model."],"exampleFix":"// before\nupdateCells(model, columnId, rawData); // rawData may contain '__proto__'\n\n// after\nconst FORBIDDEN = new Set(['__proto__', 'constructor', 'prototype']);\nconst safe = Object.fromEntries(\n  Object.entries(rawData).filter(([k]) => k && !FORBIDDEN.has(k))\n);\nupdateCells(model, columnId, safe);","handlingStrategy":"validation","validationCode":"const FORBIDDEN = new Set(['__proto__', 'constructor', 'prototype']);\nfunction sanitizeCells(cells) {\n  return Object.fromEntries(\n    Object.entries(cells).filter(([k]) => typeof k === 'string' && k && !FORBIDDEN.has(k))\n  );\n}\nupdateCells(model, columnId, sanitizeCells(rawCells));","typeGuard":"const FORBIDDEN = new Set(['__proto__', 'constructor', 'prototype']);\nfunction isSafeRowId(id: string): boolean {\n  return !!id && !FORBIDDEN.has(id);\n}","tryCatchPattern":null,"preventionTips":["Sanitise all external row ids before writing to the cells map.","Prefer Object.create(null) for any record passed as cells.","Validate imported CSV/JSON row headers against an allow-list pattern."],"tags":["security","prototype-pollution","database","input-validation"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}