Decoding a CAR from a streaming source (CarBlockIterator.fromIterable / fromStream, CarReader.fromIterable) reads a varint length, then buffers that many bytes into one contiguous allocation via reader.exactly(length) before yielding anything. This happens for the header, each block section, and each CID multihash, and none of those lengths is bounded, so a malicious CAR can declare a huge length and force a near-arbitrary allocation. The caller can't prevent it: a block is only visible once fully materialized, so a downstream size check runs too late. (The in-memory CarReader.fromBytes path is unaffected; it slices an already-bounded buffer.)
Proposal: an opt-in cap, off by default so nothing changes for existing callers, on any single contiguous read, which covers all three cases in one place:
CarBlockIterator.fromIterable(source, { maxReadLength })
It would throw right after decoding a length varint larger than the cap, before reader.exactly(length) reads the section, so an oversized section is rejected from its length prefix with none of its body buffered.
Happy to open a PR (we hit this decoding CARs from untrusted peers), just let me know your preferred name/shape.
Decoding a CAR from a streaming source (
CarBlockIterator.fromIterable/fromStream,CarReader.fromIterable) reads a varint length, then buffers that many bytes into one contiguous allocation viareader.exactly(length)before yielding anything. This happens for the header, each block section, and each CID multihash, and none of those lengths is bounded, so a malicious CAR can declare a huge length and force a near-arbitrary allocation. The caller can't prevent it: a block is only visible once fully materialized, so a downstream size check runs too late. (The in-memoryCarReader.fromBytespath is unaffected; it slices an already-bounded buffer.)Proposal: an opt-in cap, off by default so nothing changes for existing callers, on any single contiguous read, which covers all three cases in one place:
It would throw right after decoding a length varint larger than the cap, before
reader.exactly(length)reads the section, so an oversized section is rejected from its length prefix with none of its body buffered.Happy to open a PR (we hit this decoding CARs from untrusted peers), just let me know your preferred name/shape.