Avro Decoder, Memory Exhaustion, CVE-2023-37475 (critical)

Listen to this Post

The vulnerability exists in the Avro map decoder which reads attacker‑controlled block‑element counts from the wire. Prior to the fix, the decoder enforced no upper bound on the total number of map entries. It accepted a single block declaring an enormous element count (e.g., 2³¹−1) and called `make(map[…]…, n)` pre‑allocating memory until OOM. Worse, Avro allows chunking – a logical map can be split into many small blocks, each below any per‑block threshold. Without cumulative tracking, an attacker can send thousands of small blocks whose cumulative entries exceed memory, and the decoder grows the map block by block. The slice decoder already had `Config.MaxSliceAllocSize` for array attacks, but the map decoder was missing a symmetric limit. The fix introduces `Config.MaxMapAllocSize` with cumulative enforcement across block headers. However, the fix is opt‑in – default zero preserves unbounded behaviour for backward compatibility. Upgrading to v2.33.0 alone does not mitigate; users must explicitly set MaxMapAllocSize. Two decoder variants were affected: `mapDecoder.Decode` (string‑keyed maps) and `mapDecoderUnmarshaler.Decode` (TextUnmarshaler‑keyed maps). The cumulative check sits at each block header before any allocation, rejecting a block if the running total would exceed the configured cap. Without this, a producer can exhaust process memory, triggering the OOM killer.

dailycve form:

Platform: Go (hamba/avro)
Version: ≤ v2.31.0
Vulnerability: Unbounded map allocation
Severity: Critical
date: 2026-05-06

Prediction: Already patched v2.33.0

What Undercode Say:

Check vulnerable dependency
go list -m github.com/hamba/avro/v2 | grep -E 'v2.([0-2].|3[bash].)'
Test cumulative cap (set MaxMapAllocSize=10000)
cat > main.go <<EOF
package main
import ( "github.com/iskorotkov/avro/v2"; "strings" )
func main() {
cfg := avro.Config{MaxMapAllocSize: 10000}.Freeze()
schema := `{"type":"map","values":"int"}`
reader := strings.NewReader("\x02\x14\x00\x02\x14\x00") // two blocks of 20 each
dec := cfg.NewDecoder(avro.MustParseSchema(schema), reader)
var m map[bash]int
if err := dec.Decode(&m); err != nil {
println("rejected:", err.Error()) // cumulative 20+20 > 10000? Actually 40 < 10000, adjust.
}
}
EOF
go run main.go
Simulate chunking attack with cumulative exceed
100 blocks each declaring 101 entries, cap=10000 → rejects at block 100

Exploit:

Send crafted Avro binary with multiple map blocks. Each block header declares a small element count (e.g., 5000) but total blocks make cumulative entries exceed available memory. Example wire: `0x02` (block count 2) `0x88 0x9A 0x0C` (varint 100000) then truncated data. No authentication needed.

Protection from this CVE

Migrate to `github.com/iskorotkov/avro/v2 >= v2.33.0` and set `MaxMapAllocSize` explicitly (e.g., 10× legitimate map size). Use frozen config per decoder. For existing import path, add `replace github.com/hamba/avro/v2 => github.com/iskorotkov/avro/v2 v2.33.0` in go.mod. If upgrade impossible, run decoder in memory‑constrained container (cgroup) with per‑request deadline.

Impact

Remote attacker exhausts all available memory, causing OOM killer to terminate the process. Results in denial of service. No data corruption or code execution, but service availability completely lost. Chunked payloads bypass naive per‑block limits, forcing even large‑memory instances to crash.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top