0xiviel/poc-avro-cython-overflow
PoC: fastavro Cython read_long() Integer Overflow Summary The fastavro Cython extension's read_long() function uses a 64-bit unsigned integer (ulong64) for the varint accumulator. When a crafted varint has more than 9 continuation bytes (shift >= 70 bits), the shift operation causes undefined behavior in C, producing completely wrong decoded values. Confirmed on fastavro 1.12.1 — Cython and Python produce different results for the same input. Root… See the full description on the dataset page: https://huggingface.co/datasets/0xiviel/poc-avro-cython-overflow.
PoC: fastavro Cython read_long() Integer Overflow
Summary
The fastavro Cython extension's read_long() function uses a 64-bit unsigned integer (ulong64) for the varint accumulator. When a crafted varint has more than 9 continuation bytes (shift >= 70 bits), the shift operation causes undefined behavior in C, producing completely wrong decoded values.
Confirmed on fastavro 1.12.1 — Cython and Python produce different results for the same input.
Root Cause
fastavro/_read.pyx, function read_long():
ctypedef unsigned long long ulong64
# ...
n |= (b & 0x7F) << shift # UB when shift >= 64The Apache Avro C reference implementation limits varints to MAX_VARINT_BUF_SIZE=10 bytes. fastavro has no such limit.
Demonstrated Mismatch
Impact
- Data corruption: crafted
.avrofiles decode to attacker-controlled values - Behavior divergence: Cython (default) and Python fallback produce different results
- Spec violation: overlong varints should be rejected per Avro specification
Files
poc_cython_overflow.py— demonstrates overflow + enum bypass + read_fixed(-1)
Reproduction
pip install fastavro
python poc_cython_overflow.pyAffected Versions
fastavro <= 1.12.1 with Cython extension (default on CPython).
