{"record":{"id":"dbc2fd7e5aa22f3d","repo":"JuliusBrussee/caveman","slug":"invalid-decompression-limit-d","errorCode":null,"errorMessage":"invalid decompression limit %d","messagePattern":"invalid decompression limit (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/objectstore/compress.go","lineNumber":68,"sourceCode":"\t\treturn zstdEnc.EncodeAll(data, nil), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown compression codec %q\", codec)\n\t}\n}\n\n// Decompress reverses Compress with a defensive default expansion ceiling. An\n// unknown codec fails closed.\nfunc Decompress(codec string, data []byte) ([]byte, error) {\n\treturn DecompressLimit(codec, data, DefaultMaxDecompressedBytes)\n}\n\n// DecompressLimit reverses Compress while refusing to produce more than\n// maxBytes of plaintext. The limit is applied while decoding gzip and through\n// zstd's decoder memory bound, so highly-compressible hostile payloads cannot\n// first allocate their full expanded size and only then be rejected.\nfunc DecompressLimit(codec string, data []byte, maxBytes int64) ([]byte, error) {\n\tif maxBytes < 0 || maxBytes > DefaultMaxDecompressedBytes {\n\t\treturn nil, fmt.Errorf(\"invalid decompression limit %d\", maxBytes)\n\t}\n\tswitch codec {\n\tcase CompressionNone, \"\":\n\t\tif int64(len(data)) > maxBytes {\n\t\t\treturn nil, ErrDecompressedTooLarge\n\t\t}\n\t\treturn data, nil\n\tcase CompressionGzip:\n\t\tzr, err := gzip.NewReader(bytes.NewReader(data))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"gzip reader: %w\", err)\n\t\t}\n\t\tdefer zr.Close()\n\t\tout, err := io.ReadAll(io.LimitReader(zr, maxBytes+1))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"gzip read: %w\", err)\n\t\t}\n\t\tif int64(len(out)) > maxBytes {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/shared/platform/objectstore/compress.go#L50-L86","documentation":"DecompressLimit rejects a maxBytes ceiling that is negative or above the DefaultMaxDecompressedBytes cap (128 MiB). The at-fault input is the caller-supplied limit itself: callers with trusted metadata may lower the bound but may not raise it past the defensive default, preventing a caller from accidentally disabling the decompression-bomb protection.","triggerScenarios":"Thrown at shared/platform/objectstore/compress.go:68 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Pass a limit between 0 and DefaultMaxDecompressedBytes (128 MiB)","Use Decompress (no explicit limit) if the default ceiling is what you want","Fix the size-metadata source that produced a negative or oversized limit value"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}