YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
Avro logical-type readers: uncaught OverflowError/ValueError DoS from a ~130-byte container file
Target: fastavro β verified against 1.12.2 (default C/Cython reader). Same defect confirmed cross-library in apache-avro (Python) 1.12.1.
Class: Uncaught native exception (Denial of Service) on unvalidated attacker-controlled date/time values in Avro logical-type readers.
Severity: Medium (DoS). A ~110β135 byte Avro object-container file crashes any consumer that iterates fastavro.reader() (or apache-avro DataFileReader) without an ad-hoc except OverflowError/ValueError wrapper that the API does not document as necessary.
Root cause
fastavro's logical-type readers convert the stored primitive to a Python datetime/date/time with no range validation. data is the raw long/int decoded straight from the file and is fully attacker-controlled β the writer schema, including its logicalType annotation, is embedded in the object-container header, so no reader-side schema cooperation is needed.
_logical_readers.pyx (compiled; .py equivalents in _read_py.py):
def read_timestamp_millis(data, writer_schema, reader_schema):
return epoch + timedelta(microseconds=data * 1000) # OverflowError
def read_date(data, writer_schema, reader_schema):
return date.fromordinal(data + DAYS_SHIFT) # OverflowError
Any value that is a perfectly legal Avro long/int but outside Python's datetime/time domain makes the underlying CPython conversion raise a non-Avro OverflowError or ValueError.
In read_data (fastavro/_read_py.py:660-664, compiled _read.pyx) the logical-reader call
fn(data, writer_schema, reader_schema)
is NOT wrapped in the try/except that guards the primitive read (only StructError is caught there). So the exception propagates uncaught out of fastavro.reader() and crashes the consuming application. The same defect exists in apache-avro at avro/io.py:361.
Distinct from the other three Avro findings
This is a separate code path and root cause from the previously reported Avro bugs:
- Not codec/decompression β the PoC files use
avro.codec = null. - Not schema recursion β the schemas are flat scalars (
{"type":"long","logicalType":"timestamp-millis"}). - Not the container per-block
block_countloop β the crash is in logical-type value conversion in_logical_readers, before any looping over objects.
Proof of Concept
Hand-build a minimal Avro object-container file (mk.py / build_pocs.py): magic Obj\x01 + meta map carrying avro.schema and avro.codec=null + 16-byte sync + one data block (object_count=1). Writer schema = a scalar with a logicalType; value = a large-but-legal zig-zag long/int.
import fastavro
list(fastavro.reader(open('poc_ts_overflow.avro', 'rb'))) # crashes
Verified crashing values (fastavro 1.12.2 default reader):
| logical type | value | result |
|---|---|---|
| timestamp-millis | 4611686018427387903 (~2^62) | OverflowError @ _logical_readers.pyx:24 |
| timestamp-micros | (same) | OverflowError: date value out of range @ :34 |
| local-timestamp-millis | (same) | OverflowError @ :29 |
| date | 2147483647 | OverflowError: signed integer is greater than maximum @ :43 |
| time-millis | (large) | ValueError: hour must be in 0..23 @ :67 |
| time-micros | (large) | ValueError: hour must be in 0..23 @ :75 |
Negative control: an equivalent file with a legit timestamp-millis value (1600000000000) decodes cleanly to datetime(2020,9,13,12,26,40, tzinfo=UTC) in both libraries β proving the file format is valid and only the out-of-range value triggers the crash.
Cross-library control: apache-avro 1.12.1 DataFileReader raises the identical OverflowError on the same file, while decoding the legit file fine.
Captured evidence (verbatim)
=== fastavro version ===
1.12.2
=== NEGATIVE CONTROL (legit timestamp) ===
[datetime.datetime(2020, 9, 13, 12, 26, 40, tzinfo=datetime.timezone.utc)]
=== CRASH (full uncaught traceback, default reader) ===
Traceback (most recent call last):
File "<string>", line 2, in <module>
list(fastavro.reader(open('poc_ts_overflow.avro','rb')))
File "fastavro/_read.pyx", line 974, in _iter_avro_records
File "fastavro/_read.pyx", line 802, in fastavro._read._read_data
File "fastavro/_logical_readers.pyx", line 22, in fastavro._logical_readers.read_timestamp_millis
File "fastavro/_logical_readers.pyx", line 24, in fastavro._logical_readers.read_timestamp_millis
OverflowError: Python int too large to convert to C int
--- class sweep (fastavro 1.12.2, one file each, sizes shown) ---
date 112B -> OverflowError: signed integer is greater than maximum @ _logical_readers.pyx:43
time-millis 119B -> ValueError: hour must be in 0..23 @ _logical_readers.pyx:67
time-micros 124B -> ValueError: hour must be in 0..23 @ _logical_readers.pyx:75
ts-millis 129B -> OverflowError: Python int too large to convert to C int @ _logical_readers.pyx:24
ts-micros 129B -> OverflowError: date value out of range @ _logical_readers.pyx:34
local-ts-millis 135B -> OverflowError: Python int too large to convert to C int @ _logical_readers.pyx:29
--- cross-library (apache avro 1.12.1 DataFileReader) ---
poc_ts_legit.avro -> [datetime.datetime(2020, 9, 13, 12, 26, 40, tzinfo=UTCTzinfo)]
poc_ts_overflow.avro -> OverflowError : Python int too large to convert to C int @ io.py:361
Files in this repo
mk.pyβ minimal Avro object-container builder (zig-zag long, container framing).build_pocs.pyβ generates the PoC + negative-control files.poc_ts_overflow.avroβ timestamp-millis overflow crash (~129 B).poc_ts_legit.avroβ negative control, decodes cleanly.lt_date.avro,lt_time-millis.avro,lt_time-micros.avro,lt_ts-millis.avro,lt_ts-micros.avro,lt_local-ts-millis.avroβ one crashing file per logical type.
Impact & fix
Any service that ingests untrusted .avro files (data pipelines, ML feature stores, event consumers) and iterates fastavro.reader() is crashed by a tiny file. Because the exception type is OverflowError/ValueError β not a documented Avro decode error β generic except (ValueError, ...) handlers that developers write around "parse errors" often do not catch it, and even those that do are working around undocumented behavior.
Suggested fix: wrap the logical-reader dispatch in read_data so any conversion exception is re-raised as a catchable Avro error (or clamp/validate the value against the datetime domain before conversion).
Dedup note
Distinct from prior Avro reports on this account (decompression bomb, schema-recursion DoS, container block-count loop DoS) β different code path (_logical_readers), different trigger (in-domain-illegal date/time value), null codec, flat scalar schema. No public CVE known for fastavro logical-type range validation as of packaging date.