VYPR
High severityNVD Advisory· Published Jul 17, 2023· Updated Oct 18, 2024

Attacker-controlled parameter can cause denial of service in hamba avro

CVE-2023-37475

Description

Hamba avro is a go lang encoder/decoder implementation of the avro codec specification. In affected versions a well-crafted string passed to avro's github.com/hamba/avro/v2.Unmarshal() can throw a fatal error: runtime: out of memory which is unrecoverable and can cause denial of service of the consumer of avro. The root cause of the issue is that avro uses part of the input to Unmarshal() to determine the size when creating a new slice and hence an attacker may consume arbitrary amounts of memory which in turn may cause the application to crash. This issue has been addressed in commit b4a402f4 which has been included in release version 2.13.0. Users are advised to upgrade. There are no known workarounds for this vulnerability.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Crafted input to Hamba avro's Unmarshal causes out-of-memory crash via attacker-controlled slice size, leading to DoS.

The vulnerability resides in the github.com/hamba/avro/v2.Unmarshal() function, which uses part of the input data to determine the size when creating a new slice. An attacker can craft a string that specifies an extremely large size, causing the library to allocate an arbitrary amount of memory, resulting in a fatal out-of-memory error and a denial of service [1][3].

To exploit this, an attacker only needs to supply a malicious input to any application that calls Unmarshal() on attacker-controlled data. No authentication or special privileges are required, making the attack surface broad. The issue was discovered during a security audit of Dapr, which uses the avro library [1].

The impact is a complete denial of service: the application crashes with an unrecoverable runtime error, affecting availability. There is no risk of data confidentiality or integrity loss, but the crash can disrupt services relying on the avro library [3].

The issue has been fixed in commit b4a402f4 included in release version 2.13.0 [1][3]. Users are advised to upgrade. However, note that the repository has been archived and is no longer maintained [2]. The fix introduced a configurable maximum byte slice size via a pull request [4]. No known workarounds exist for unpatched versions [1].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/hamba/avroGo
< 2.13.02.13.0
github.com/hamba/avro/v2Go
< 2.13.02.13.0

Affected products

9

Patches

1
b4a402f41cf4

feat: add max byte slice size config (#273)

https://github.com/hamba/avroNicholas WiersmaJul 16, 2023via ghsa
4 files changed · +55 1
  • config.go+14 0 modified
    @@ -8,6 +8,8 @@ import (
     	"github.com/modern-go/reflect2"
     )
     
    +const maxByteSliceSize = 1024 * 1024
    +
     // DefaultConfig is the default API.
     var DefaultConfig = Config{}.Freeze()
     
    @@ -43,6 +45,10 @@ type Config struct {
     	// Disable caching layer for encoders and decoders, forcing them to get rebuilt on every
     	// call to Marshal() and Unmarshal()
     	DisableCaching bool
    +
    +	// MaxByteSliceSize is the maximum size of `bytes` or `string` types the Reader will create, defaulting to 1MiB.
    +	// If this size is exceeded, the Reader returns an error. This can be disabled by setting a negative number.
    +	MaxByteSliceSize int
     }
     
     // Freeze makes the configuration immutable.
    @@ -252,3 +258,11 @@ func (c *frozenConfig) getBlockLength() int {
     	}
     	return blockSize
     }
    +
    +func (c *frozenConfig) getMaxByteSliceSize() int {
    +	size := c.config.MaxByteSliceSize
    +	if size == 0 {
    +		return maxByteSliceSize
    +	}
    +	return size
    +}
    
  • reader.go+8 1 modified
    @@ -4,6 +4,7 @@ import (
     	"errors"
     	"fmt"
     	"io"
    +	"strings"
     	"unsafe"
     )
     
    @@ -216,12 +217,18 @@ func (r *Reader) ReadString() string {
     func (r *Reader) readBytes(op string) []byte {
     	size := int(r.ReadLong())
     	if size < 0 {
    -		r.ReportError("ReadString", "invalid "+op+" length")
    +		fnName := "Read" + strings.ToTitle(op)
    +		r.ReportError(fnName, "invalid "+op+" length")
     		return nil
     	}
     	if size == 0 {
     		return []byte{}
     	}
    +	if max := r.cfg.getMaxByteSliceSize(); max > 0 && size > max {
    +		fnName := "Read" + strings.ToTitle(op)
    +		r.ReportError(fnName, "size is greater than `Config.MaxByteSliceSize`")
    +		return nil
    +	}
     
     	// The bytes are entirely in the buffer and of a reasonable size.
     	// Use the byte slab.
    
  • reader_test.go+26 0 modified
    @@ -507,6 +507,19 @@ func TestReader_ReadBytes(t *testing.T) {
     	}
     }
     
    +func TestReader_ReadBytesLargerThanMaxByteSliceSize(t *testing.T) {
    +	data := []byte{
    +		246, 255, 255, 255, 255, 10, 255, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    +		32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    +		32, 32, 32, 32, 32, 32, 32,
    +	}
    +	r := avro.NewReader(bytes.NewReader(data), 4)
    +
    +	_ = r.ReadBytes()
    +
    +	assert.Error(t, r.Error)
    +}
    +
     func TestReader_ReadString(t *testing.T) {
     	tests := []struct {
     		data    []byte
    @@ -583,6 +596,19 @@ func TestReader_ReadString(t *testing.T) {
     	}
     }
     
    +func TestReader_ReadStringLargerThanMaxByteSliceSize(t *testing.T) {
    +	data := []byte{
    +		246, 255, 255, 255, 255, 10, 255, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    +		32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    +		32, 32, 32, 32, 32, 32, 32,
    +	}
    +	r := avro.NewReader(bytes.NewReader(data), 4)
    +
    +	_ = r.ReadString()
    +
    +	assert.Error(t, r.Error)
    +}
    +
     func TestReader_ReadStringFastPathIsntBoundToBuffer(t *testing.T) {
     	data := []byte{0x06, 0x66, 0x6F, 0x6F, 0x08, 0x61, 0x76, 0x72, 0x6F}
     	r := avro.NewReader(bytes.NewReader(data), 4)
    
  • README.md+7 0 modified
    @@ -125,11 +125,18 @@ encoding and decoding.
     Enums may also implement `TextMarshaler` and `TextUnmarshaler`, and must resolve to valid symbols in the given enum schema.
     
     ##### Identical Underlying Types
    +
     One type can be [ConvertibleTo](https://go.dev/ref/spec#Conversions) another type if they have identical underlying types. 
     A non-native type is allowed be used if it can be convertible to *time.Time*, *big.Rat* or *avro.LogicalDuration* for the particular of *LogicalTypes*.
     
     Ex.: `type Timestamp time.Time`
     
    +##### Untrusted Input With Bytes and Strings
    +
    +For security reasons, the configuration `Config.MaxByteSliceSize` restricts the maximum size of `bytes` and `string` types created
    +by the `Reader`. The default maximum size is `1MiB` and is configurable. This is required to stop untrusted input from consuming all memory and
    +crashing the application. Should this not be need, setting a negative number will disable the behaviour.
    +
     ### Recursive Structs
     
     At this moment recursive structs are not supported. It is planned for the future.
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.