CVE-2025-30153
Description
kin-openapi is a Go project for handling OpenAPI files. Prior to 0.131.0, when validating a request with a multipart/form-data schema, if the OpenAPI schema allows it, an attacker can upload a crafted ZIP file (e.g., a ZIP bomb), causing the server to consume all available system memory. The root cause comes from the ZipFileBodyDecoder, which is registered automatically by the module (contrary to what the documentation says). This vulnerability is fixed in 0.131.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/getkin/kin-openapiGo | < 0.131.0 | 0.131.0 |
Patches
167f0b233ffc0openapi3filter: de-register ZipFileBodyDecoder and make a few decoders public (#1059)
5 files changed · +36 −20
.github/docs/openapi3filter.txt+12 −0 modified@@ -42,6 +42,9 @@ FUNCTIONS func ConvertErrors(err error) error ConvertErrors converts all errors to the appropriate error format. +func CsvBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) + CsvBodyDecoder is a body decoder that decodes a csv body to a string. + func DefaultErrorEncoder(_ context.Context, err error, w http.ResponseWriter) DefaultErrorEncoder writes the error to the ResponseWriter, by default a content type of text/plain, a body of the plain text of the error, and a @@ -58,9 +61,11 @@ func JSONBodyDecoder(body io.Reader, header http.Header, schema *openapi3.Schema JSONBodyDecoder decodes a JSON formatted body. It is public so that is easy to register additional JSON based formats. +func MultipartBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) func NoopAuthenticationFunc(context.Context, *AuthenticationInput) error NoopAuthenticationFunc is an AuthenticationFunc +func PlainBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) func RegisterBodyDecoder(contentType string, decoder BodyDecoder) RegisterBodyDecoder registers a request body's decoder for a content type. @@ -84,6 +89,7 @@ func UnregisterBodyDecoder(contentType string) func UnregisterBodyEncoder(contentType string) UnregisterBodyEncoder disables package-wide decoding of contentType values +func UrlencodedBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) func ValidateParameter(ctx context.Context, input *RequestValidationInput, parameter *openapi3.Parameter) error ValidateParameter validates a parameter's value by JSON schema. The function returns RequestError with a ParseError cause when unable to parse a value. @@ -121,6 +127,12 @@ func ValidateSecurityRequirements(ctx context.Context, input *RequestValidationI requirements in order and returns nil on the first valid requirement. If no requirement is met, errors are returned in order. +func YamlBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) +func ZipFileBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) + ZipFileBodyDecoder is a body decoder that decodes a zip file body to a + string. Use with caution as this implementation may be susceptible to a zip + bomb attack. + TYPES
openapi3filter/req_resp_decoder.go+15 −15 modified@@ -1269,16 +1269,15 @@ func init() { RegisterBodyDecoder("application/vnd.api+json", JSONBodyDecoder) RegisterBodyDecoder("application/octet-stream", FileBodyDecoder) RegisterBodyDecoder("application/problem+json", JSONBodyDecoder) - RegisterBodyDecoder("application/x-www-form-urlencoded", urlencodedBodyDecoder) - RegisterBodyDecoder("application/x-yaml", yamlBodyDecoder) - RegisterBodyDecoder("application/yaml", yamlBodyDecoder) - RegisterBodyDecoder("application/zip", zipFileBodyDecoder) - RegisterBodyDecoder("multipart/form-data", multipartBodyDecoder) - RegisterBodyDecoder("text/csv", csvBodyDecoder) - RegisterBodyDecoder("text/plain", plainBodyDecoder) + RegisterBodyDecoder("application/x-www-form-urlencoded", UrlencodedBodyDecoder) + RegisterBodyDecoder("application/x-yaml", YamlBodyDecoder) + RegisterBodyDecoder("application/yaml", YamlBodyDecoder) + RegisterBodyDecoder("multipart/form-data", MultipartBodyDecoder) + RegisterBodyDecoder("text/csv", CsvBodyDecoder) + RegisterBodyDecoder("text/plain", PlainBodyDecoder) } -func plainBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { +func PlainBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { data, err := io.ReadAll(body) if err != nil { return nil, &ParseError{Kind: KindInvalidFormat, Cause: err} @@ -1298,15 +1297,15 @@ func JSONBodyDecoder(body io.Reader, header http.Header, schema *openapi3.Schema return value, nil } -func yamlBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { +func YamlBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { var value any if err := yaml.NewDecoder(body).Decode(&value); err != nil { return nil, &ParseError{Kind: KindInvalidFormat, Cause: err} } return value, nil } -func urlencodedBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { +func UrlencodedBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { // Validate schema of request body. // By the OpenAPI 3 specification request body's schema must have type "object". // Properties of the schema describes individual parts of request body. @@ -1391,7 +1390,7 @@ func decodeProperty(dec valueDecoder, name string, prop *openapi3.SchemaRef, enc return decodeValue(dec, name, sm, prop, false) } -func multipartBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { +func MultipartBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { if !schema.Value.Type.Is("object") { return nil, errors.New("unsupported schema of request body") } @@ -1519,8 +1518,9 @@ func FileBodyDecoder(body io.Reader, header http.Header, schema *openapi3.Schema return string(data), nil } -// zipFileBodyDecoder is a body decoder that decodes a zip file body to a string. -func zipFileBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { +// ZipFileBodyDecoder is a body decoder that decodes a zip file body to a string. +// Use with caution as this implementation may be susceptible to a zip bomb attack. +func ZipFileBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { buff := bytes.NewBuffer([]byte{}) size, err := io.Copy(buff, body) if err != nil { @@ -1569,8 +1569,8 @@ func zipFileBodyDecoder(body io.Reader, header http.Header, schema *openapi3.Sch return string(content), nil } -// csvBodyDecoder is a body decoder that decodes a csv body to a string. -func csvBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { +// CsvBodyDecoder is a body decoder that decodes a csv body to a string. +func CsvBodyDecoder(body io.Reader, header http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (any, error) { r := csv.NewReader(body) var sb strings.Builder
openapi3filter/validate_request.go+3 −3 modified@@ -113,9 +113,9 @@ func appendToQueryValues[T any](q url.Values, parameterName string, v []T) { } func joinValues(values []any, sep string) string { - strValues := make([]string, len(values)) - for i, v := range values { - strValues[i] = fmt.Sprintf("%v", v) + strValues := make([]string, 0, len(values)) + for _, v := range values { + strValues = append(strValues, fmt.Sprintf("%v", v)) } return strings.Join(strValues, sep) }
openapi3filter/zip_file_upload_test.go+2 −0 modified@@ -17,6 +17,8 @@ import ( ) func TestValidateZipFileUpload(t *testing.T) { + openapi3filter.RegisterBodyDecoder("application/zip", openapi3filter.ZipFileBodyDecoder) + const spec = ` openapi: 3.0.0 info:
README.md+4 −2 modified@@ -130,8 +130,7 @@ func main() { ## Custom content type for body of HTTP request/response -By default, the library parses a body of the HTTP request and response -if it has one of the following content types: `"text/plain"` or `"application/json"`. +By default, the library parses a body of the HTTP request and response of [a few content types](https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1264) e.g. `"text/plain"` or `"application/json"`. To support other content types you must register decoders for them: ```go @@ -295,6 +294,9 @@ for _, path := range doc.Paths.InMatchingOrder() { ## CHANGELOG: Sub-v1 breaking API changes +### v0.131.0 +* No longer `openapi3filter.RegisterBodyDecoder` the `openapi3filter.ZipFileBodyDecoder` by default. + ### v0.129.0 * `openapi3.Discriminator.Mapping` and `openapi3.OAuthFlow.Scopes` fields went from a `map[string]string` to the new type `StringMap`
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-wq9g-9vfc-cfq9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-30153ghsaADVISORY
- github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.gonvdWEB
- github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.gonvdWEB
- github.com/getkin/kin-openapi/commit/67f0b233ffc01332f7d993f79490fbea5f4455f1nvdWEB
- github.com/getkin/kin-openapi/pull/1059ghsaWEB
- github.com/getkin/kin-openapi/security/advisories/GHSA-wq9g-9vfc-cfq9nvdWEB
News mentions
0No linked articles in our index yet.