CVE-2024-28180 (Go, published 2024-03-09T01:15Z)
Description: value: Package jose aims to provide an implementation of the Javascript Object Signing and Encryption set of standards. An attacker could send a JWE containing compressed data that used large amounts of memory and CPU when decompressed by Decrypt or DecryptMulti. Those functions now return an error if the decompressed data would exceed 250kB or 10x the compressed size (whichever is larger). This vulnerability has been patched in versions 4.0.1, 3.0.3 and 2.6.3.

Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/go-jose/go-jose
Files changed:
CHANGELOG.md
crypter.go
encoding.go
encoding_test.go
Commit message: jwe: limit maximum output from decompressing (#106)



Vulnerable code:
// Compress with DEFLATE
// Decompress with DEFLATE
	_, err := io.Copy(output, reader)
	if err != nil {

Fixed code:
# v4.0.1

## Fixed

 - An attacker could send a JWE containing compressed data that used large
   amounts of memory and CPU when decompressed by `Decrypt` or `DecryptMulti`.
   Those functions now return an error if the decompressed data would exceed
   250kB or 10x the compressed size (whichever is larger). Thanks to
   Enze Wang@Alioth and Jianjun Chen@Zhongguancun Lab (@zer0yu and @chenjj)
   for reporting.

//
// Automatically decompresses plaintext, but returns an error if the decompressed
// data would be >250kB or >10x the size of the compressed data, whichever is larger.
//
// Automatically decompresses plaintext, but returns an error if the decompressed
// data would be >250kB or >3x the size of the compressed data, whichever is larger.
	"fmt"
// deflate compresses the input.
// inflate decompresses the input.
//
// Errors if the decompressed data would be >250kB or >10x the size of the
// compressed data, whichever is larger.
	maxCompressedSize := max(250_000, 10*int64(len(input)))

	limit := maxCompressedSize + 1
	n, err := io.CopyN(output, reader, limit)
	if err != nil && err != io.EOF {
	if n == limit {
		return nil, fmt.Errorf("uncompressed data would be too large (>%d bytes)", maxCompressedSize)
	}
	"crypto/rand"
	"io"
// TestLargeZip tests that we can decompress a large input, so long as its
// compression ratio is reasonable.
func TestLargeZip(t *testing.T) {
	input := new(bytes.Buffer)
	_, err := io.CopyN(input, rand.Reader, 251_000)
	if err != nil {
		t.Fatalf("generating input: %s", err)
	}
	compressed, err := compress(DEFLATE, input.Bytes())
	if err != nil {
		t.Errorf("compressing: %s", err)
	}
	t.Logf("compression ratio: %g", float64(len(input.Bytes()))/float64(len(compressed)))
	_, err = decompress(DEFLATE, compressed)
	if err != nil {
		t.Errorf("decompressing large input with low compression ratio: %s", err)
	}
}

func TestZipBomb(t *testing.T) {
	input := strings.Repeat("a", 251_000)
	compressed, err := compress(DEFLATE, []byte(input))
	if err != nil {
		t.Errorf("compressing: %s", err)
	}
	t.Logf("compression ratio: %d %g", len(compressed), float64(len(input))/float64(len(compressed)))
	out, err := decompress(DEFLATE, compressed)
	if err == nil {
		t.Errorf("expected error decompressing zip bomb, got none. output size %d", len(out))
	}
}