{"record":{"id":"b0b65ca87d1fedc6","repo":"mongodb/node-mongodb-native","slug":"attempt-to-access-memory-outside-buffer-bounds-bu","errorCode":null,"errorMessage":"Attempt to access memory outside buffer bounds: buffer length: ${buffer.length}, offset: ${offset}, length: ${length}","messagePattern":"Attempt to access memory outside buffer bounds: buffer length: (.+?), offset: (.+?), length: (.+?)","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"src/bson.ts","lineNumber":45,"sourceCode":"  ObjectId,\n  type ObjectIdLike,\n  serialize,\n  Timestamp,\n  UUID\n} from 'bson';\n\n/** @internal */\nexport type BSONElement = BSON.OnDemand['BSONElement'];\n\nexport function parseToElementsToArray(bytes: Uint8Array, offset?: number): BSONElement[] {\n  const res = BSON.onDemand.parseToElements(bytes, offset);\n  return Array.isArray(res) ? res : [...res];\n}\n\n// validates buffer inputs, used for read operations\nconst validateBufferInputs = (buffer: Uint8Array, offset: number, length: number) => {\n  if (offset < 0 || offset + length > buffer.length) {\n    throw new RangeError(\n      `Attempt to access memory outside buffer bounds: buffer length: ${buffer.length}, offset: ${offset}, length: ${length}`\n    );\n  }\n};\n\n// readInt32LE, reads a 32-bit integer from buffer at given offset\n// throws if offset is out of bounds\nexport const readInt32LE = (buffer: Uint8Array, offset: number): number => {\n  validateBufferInputs(buffer, offset, 4);\n  return NumberUtils.getInt32LE(buffer, offset);\n};\n\n// readUint8, reads a single unsigned byte from buffer at given offset\nexport const readUint8 = (buffer: Uint8Array, offset: number): number => {\n  validateBufferInputs(buffer, offset, 1);\n  return buffer[offset];\n};\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/bson.ts#L27-L63","documentation":"Thrown as a RangeError by the internal validateBufferInputs guard in src/bson.ts when a BSON read helper (readInt32LE / readUint8) is asked to read at an offset that is negative or where offset+length exceeds the buffer length. The driver uses this to fail fast on malformed or truncated BSON byte buffers during deserialization. It indicates the bytes presented to the parser do not contain a well-formed BSON document at the requested location.","triggerScenarios":"A Uint8Array that is too short (or an offset that points past its end) is passed to a BSON deserialization path. Concretely, calling a public API that decodes BSON (e.g. deserialize/parseToElements or an internal wire-protocol reply decoder) on a buffer that was truncated, double-sliced, or built from a mismatched length prefix. The condition is offset < 0 || offset + length > buffer.length inside validateBufferInputs at src/bson.ts:44.","commonSituations":"Hand-built or mutated wire payloads, buffers received over a stream that were cut off mid-message, a wrong length field in a custom protocol, reading from a SharedArrayBuffer/Buffer slice whose byteLength was miscomputed, or a corruption bug in code that manually advances an offset cursor while parsing BSON. Rarely seen in normal driver use; usually surfaces in tests, proxy tools, or when a user deserializes raw bytes from a non-driver source.","solutions":["Verify the byte length of the Uint8Array you are deserializing before parsing; log buffer.length, offset, and the length prefix stored in the first 4 bytes to find the mismatch.","Ensure the buffer was not truncated during transport (check socket/stream framing, message-length headers, and any manual subarray/slice math).","If you compute offsets yourself, recompute them against the actual buffer.length and clamp before reading.","If parsing concatenated BSON documents, validate each document's declared size fits inside the remaining bytes before advancing."],"exampleFix":"// before: deserializing a possibly truncated buffer\nconst doc = deserialize(maybeTruncatedBytes);\n\n// after: guard on length before parsing\nfunction safeDeserialize(bytes: Uint8Array, offset = 0) {\n  if (bytes.length - offset < 5) {\n    throw new Error(`buffer too small for BSON doc: have ${bytes.length - offset} bytes`);\n  }\n  return deserialize(bytes.subarray(offset));\n}\nconst doc = safeDeserialize(maybeTruncatedBytes);","handlingStrategy":"validation","validationCode":"// Before deserializing, confirm the buffer can hold a BSON doc at the offset.\nfunction assertReadable(bytes: Uint8Array, offset: number, length: number) {\n  if (offset < 0 || offset + length > bytes.length) {\n    throw new RangeError(\n      `refusing to read: need [${offset}, ${offset + length}) of ${bytes.length}`\n    );\n  }\n}\n\n// usage\nassertReadable(buf, 0, 4);\nconst sizeLe = buf.subarray(0, 4);\nconst docSize = NumberUtils.getInt32LE(sizeLe, 0);\nassertReadable(buf, 0, docSize);","typeGuard":"// Narrow 'unknown bytes' to a non-empty, in-bounds view before parsing.\nfunction isNonEmptyBytes(b: unknown): b is Uint8Array {\n  return b instanceof Uint8Array && b.length > 0;\n}","tryCatchPattern":"try {\n  return deserialize(buf.subarray(offset));\n} catch (e) {\n  if (e instanceof RangeError && /outside buffer bounds/.test(e.message)) {\n    throw new Error(`truncated BSON input: ${buf.length} bytes, offset ${offset}`);\n  }\n  throw e;\n}","preventionTips":["Always check buffer.length and any size header before slicing or parsing BSON.","When reading concatenated BSON docs, advance an offset cursor and bound each read by the remaining bytes.","Validate stream framing / message-length prefixes before handing bytes to the parser.","Avoid reusing or mutating buffers shared with other consumers while parsing."],"tags":["bson","buffer","range-error","deserialization","internal"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}