CVE-2023-37475 (Go, published 2023-07-17T17:15Z)
Description: value: 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.
Severity: nan (CVSS v3 base score: 7.5)
Weakness: CWE-400 \u2014 Uncontrolled Resource Consumption
The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
Repository: https://github.com/hamba/avro
Files changed:
README.md
config.go
reader.go
reader_test.go
Commit message: feat: add max byte slice size config (#273)



Vulnerable code:
		r.ReportError("ReadString", "invalid "+op+" length")

Fixed code:

##### 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.

const maxByteSliceSize = 1024 * 1024


	// 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

func (c *frozenConfig) getMaxByteSliceSize() int {
	size := c.config.MaxByteSliceSize
	if size == 0 {
		return maxByteSliceSize
	}
	return size
}
	"strings"
		fnName := "Read" + strings.ToTitle(op)
		r.ReportError(fnName, "invalid "+op+" length")
	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
	}
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_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)
}