{"record":{"id":"7d3d7df7830d6f18","repo":"livekit/livekit","slug":"invalid-number-of-bits-expected-0-64","errorCode":null,"errorMessage":"invalid number of bits, expected 0-64","messagePattern":"invalid number of bits, expected 0-64","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/sfu/rtpextension/dependencydescriptor/bitstreamreader.go","lineNumber":41,"sourceCode":"\tbuf           []byte\n\tpos           int\n\tremainingBits int\n}\n\nfunc NewBitStreamReader(buf []byte) *BitStreamReader {\n\treturn &BitStreamReader{buf: buf, remainingBits: len(buf) * 8}\n}\n\nfunc (b *BitStreamReader) RemainingBits() int {\n\treturn b.remainingBits\n}\n\n// Reads `bits` from the bitstream. `bits` must be in range [0, 64].\n// Returns an unsigned integer in range [0, 2^bits - 1].\n// On failure sets `BitstreamReader` into the failure state and returns 0.\nfunc (b *BitStreamReader) ReadBits(bits int) (uint64, error) {\n\tif bits < 0 || bits > 64 {\n\t\treturn 0, errors.New(\"invalid number of bits, expected 0-64\")\n\t}\n\n\tif b.remainingBits < bits {\n\t\tb.remainingBits -= bits\n\t\treturn 0, io.EOF\n\t}\n\n\tremainingBitsInFirstByte := b.remainingBits % 8\n\tb.remainingBits -= bits\n\tif bits < remainingBitsInFirstByte {\n\t\t// Reading fewer bits than what's left in the current byte, just\n\t\t// return the portion of this byte that is needed.\n\t\toffset := remainingBitsInFirstByte - bits\n\t\treturn uint64((b.buf[b.pos] >> offset) & ((1 << bits) - 1)), nil\n\t}\n\tvar result uint64\n\tif remainingBitsInFirstByte > 0 {\n\t\t// Read all bits that were left in the current byte and consume that byte.","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/livekit/livekit/blob/ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6/pkg/sfu/rtpextension/dependencydescriptor/bitstreamreader.go#L23-L59","documentation":"ReadBits returns this error when the requested bit count is outside the valid range [0, 64], since a single read can only populate a uint64. On range failure the reader is not advanced; on insufficient-data failure it enters the failure state and returns io.EOF.","triggerScenarios":"Calling BitStreamReader.ReadBits(bits) with bits < 0 or bits > 64, directly or via callers like Parse/readMandatoryFields when a corrupt descriptor produces a computed width out of range.","commonSituations":"Malformed or hostile DependencyDescriptor RTP payloads causing negative/oversized computed widths; bit misuse after a prior parse failure left the stream in a bad state.","solutions":["Ensure ReadBits is only called with values 0-64","Validate computed bit widths from parsed fields before passing them to ReadBits","Abandon the whole parse when any bitstream error occurs (check err immediately after every read)","Sanity-check the payload length before parsing"],"exampleFix":"// before\nval, err := b.ReadBits(width) // width computed, may exceed 64\n// after\nif width < 0 || width > 64 {\n    return fmt.Errorf(\"invalid width %d\", width)\n}\nval, err := b.ReadBits(width)","handlingStrategy":"validation","validationCode":"if bits >= 0 && bits <= 64 {\n    v, err := reader.ReadBits(bits)\n}","typeGuard":null,"tryCatchPattern":"v, err := reader.ReadBits(bits)\nif err != nil {\n    return nil // abort parse; do not reuse reader\n}","preventionTips":["Abort the entire descriptor parse on the first bitstream error","Clamp computed widths derived from untrusted fields before reading","Fuzz-test the parser with random payloads"],"tags":["bitstream","parsing","validation"],"backgroundTag":"bitstream-read-out-of-range","analyzedSha":"ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6","analyzedAt":"2026-09-02T03:56:08.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}