Apache Arrow Parquet DeltaLengthByteArray CWE-770/789 unbounded-resize PoC

Proof-of-concept material for a huntr Model Format Vulnerability report against apache/arrow (C++ Parquet reader, cpp/src/parquet/decoder.cc).

Files

  • legit_reference.parquet - a real, valid 391-byte Parquet file written with pyarrow.parquet.write_table(..., column_encoding={"s": "DELTA_LENGTH_BYTE_ARRAY"}) (pyarrow 25.0.0), containing 3 short strings ("a", "bb", "ccc"). Byte offset 0x28 in this real file (verified by hex-dumping the actual output, not guessed) contains the DeltaBinaryPacked header for the length stream: 80 01 04 03 02 = block_size=128 (varint), num_mini_blocks=4 (varint), total_value_count=3 (varint, correctly matches the 3 real strings), first_value=1 (zigzag varint, matches the length of "a").

  • evil_delta_header.bin - the same 4-field DeltaBinaryPacked header encoding, re-created with the identical verified varint/zigzag format, but with total_value_count set to 2000000000 instead of 3: 80 01 04 80 a8 d6 b9 07 00 (9 bytes total).

The bug

DeltaBitPackDecoder::InitHeader (decoder.cc) validates block_size and num_mini_blocks (via values_per_block_/mini_blocks_per_block_ checks) but does not validate total_value_count_ against the actual amount of data remaining in the page. This count flows directly into DeltaLengthByteArrayDecoder::DecodeLengths(): buffered_length_->Resize(num_length * sizeof(int32_t)) - executed before the individual lengths are read/validated. The same unguarded pattern is duplicated for DELTA_BYTE_ARRAY prefixes.

Reachable from the ordinary per-page decoder dispatch in column_reader.cc - encoding is read directly from the (attacker-controlled) page header, so creating a file with a DELTA_LENGTH_BYTE_ARRAY-encoded column is a normal, documented write path (as legit_reference.parquet demonstrates), not an exotic one.

Honest limits (not swept under the rug)

evil_delta_header.bin is the isolated encoded-header fragment, byte-for-byte consistent with the real encoding verified against legit_reference.parquet - it is not a complete, self-consistent .parquet container (splicing it into a real file changes the page's byte length, which would also require recomputing the Thrift-encoded compressed_page_size/uncompressed_page_size fields that precede it - a full working end-to-end file was not built for this report). This report's confidence rests on direct reading of decoder.cc/column_reader.cc in a fresh clone, cross-checked by an independent blind-adversarial review (separate clone, neutral prompt, told to actively look for reasons this is NOT a bug) that reached the same conclusion and narrowed the practical ceiling to ~8.5GB (not the full ~17GB the uint32 field could nominally address, because int/size_t promotion raises an exception above INT_MAX rather than silently wrapping) - a DoS/OOM class finding, not memory corruption.

Impact: Denial of Service - an attacker who can supply or influence a .parquet file with a DELTA_LENGTH_BYTE_ARRAY or DELTA_BYTE_ARRAY encoded column can force a large (up to ~8.5GB), disproportionate buffer resize from a page declaring a small amount of real data.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support