eef-cve-2026-97200

CVSS 8.2 osv_hex
Description

## Summary Allocation of Resources Without Limits or Throttling vulnerability in `hackney_conn` in benoitc hackney allows a malicious HTTP server to exhaust client memory via an oversized or highly compressed response body. `hackney:request/5` and `hackney:body/1` return the whole response body, and nothing bounds how much the connection process buffers. Any server the client requests can trigger it. `hackney_conn:read_full_body/2` and the HTTP/2 and HTTP/3 accumulators append every chunk until the body ends. With `{auto_decompress, true}` the buffered body is then inflated in one step with `zlib:gunzip/1` or `zlib:inflate/2`, which return the whole output at once. This issue affects hackney: from 2.0.0-beta.1 before 4.9.0. ## Details **1. Unbounded accumulation.** `hackney:request/5` with a body, and `hackney:body/1` after `start_response/1`, read the response in `src/hackney_conn.erl` through `read_full_body/2`, which appends each chunk to a binary accumulator until the body ends. The HTTP/2 and HTTP/3 synchronous paths accumulate stream data the same way. No option caps the size. **2. One-step decompression.** With `{auto_decompress, true}` hackney sends `Accept-Encoding: gzip, deflate`. Once the body is complete, `maybe_decompress_body/2` dispatches on `Content-Encoding` to `decompress_gzip/1` (`zlib:gunzip/1`) or `decompress_deflate/1` (`zlib:inflate/2`). Both return the whole output at once, so the inflated size is bounded only by the compression ratio. The report measured a 1 MB gzip body inflating to 1 GB on hackney 4.8.4. ## Proof of concept 1. Build a gzip stream whose inflated size is 1 GB from a reused 64 KB chunk of zero bytes (deflate with window bits 31, best compression). The stream is about 1 MB on the wire. 2. Start a TCP listener on loopback that accepts one connection, reads the request, and answers `HTTP/1.1 200 OK` with `Content-Encoding: gzip`, a `Content-Length` matching the stream, `Connection: close`, and the stream as body. 3. From a node running a vulnerable hackney, call `hackney:request(get, Url, [], <<>>, [{auto_decompress, true}, with_body])` against that listener. 4. Observe the returned body of 1,048,576,000 bytes and the VM memory growing by about 1.8 GB for a 1,019,197 byte response. A larger stream, or an endless body without `auto_decompress`, drives the node out of memory. ## Impact A server the client requests can make the client allocate memory proportional to the body it sends, or to its decompressed size, until the node runs out of memory. ## Workarounds Leave `auto_decompress` disabled (the default). Without it `hackney_conn:maybe_decompress_body/2` never inflates the body, which closes the amplification half. The uncapped raw body read has no workaround.

Timeline
Published
unknown
Last Modified
unknown
CVSS Details

CVSS details not available.

Affected Products

No product information available.

Weaknesses (CWE)
References
Linked Vulnerabilities

No linked vulnerabilities found.

{
  "affected": [
    {
      "database_specific": {
        "source": "https://cna.erlef.org/osv/EEF-CVE-2026-97200.json"
      },
      "package": {
        "ecosystem": "Hex",
        "name": "hackney",
        "purl": "pkg:hex/hackney"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.0.0-beta.1"
            },
            {
              "fixed": "4.9.0"
            }
          ],
          "type": "SEMVER"
        }
      ],
      "versions": [
        "2.0.0",
        "2.0.0-beta.1",
        "2.0.1",
        "3.0.0",
        "3.0.1",
        "3.0.2",
        "3.0.3",
        "3.1.0",
        "3.1.1",
        "3.1.2",
        "3.2.0",
        "3.2.1",
        "4.0.0",
        "4.0.1",
        "4.0.2",
        "4.0.3",
        "4.1.0",
        "4.2.0",
        "4.2.1",
        "4.2.2",
        "4.2.3",
        "4.3.0",
        "4.4.0",
        "4.4.1",
        "4.4.2",
        "4.4.3",
        "4.4.5",
        "4.5.0",
        "4.5.1",
        "4.5.2",
        "4.6.0",
        "4.6.1",
        "4.7.0",
        "4.7.1",
        "4.7.2",
        "4.7.3",
        "4.7.4",
        "4.8.0",
        "4.8.1",
        "4.8.2",
        "4.8.3",
        "4.8.4",
        "4.8.5",
        "4.8.6",
        "4.8.7"
      ]
    },
    {
      "database_specific": {
        "source": "https://cna.erlef.org/osv/EEF-CVE-2026-97200.json"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "dc41b79339ca0c41e16d3f2dd17172bc2de855d6"
            },
            {
              "fixed": "493e8bf83a391548e5101792276ab3fc428fa76c"
            }
          ],
          "repo": "https://github.com/benoitc/hackney",
          "type": "GIT"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-97200"
  ],
  "credits": [
    {
      "name": "Martin Karrer",
      "type": "FINDER"
    },
    {
      "name": "Quinn Wilton",
      "type": "FINDER"
    },
    {
      "name": "Quinn Wilton",
      "type": "REPORTER"
    },
    {
      "name": "Martin Karrer",
      "type": "REMEDIATION_DEVELOPER"
    },
    {
      "name": "Benoit Chesneau",
      "type": "REMEDIATION_DEVELOPER"
    },
    {
      "name": "Jonatan Männchen / EEF",
      "type": "COORDINATOR"
    }
  ],
  "database_specific": {
    "capec_ids": [
      "CAPEC-130"
    ],
    "cpe_ids": [
      "cpe:2.3:a:benoitc:hackney:*:*:*:*:*:*:*:*"
    ],
    "cwe_ids": [
      "CWE-409",
      "CWE-770"
    ]
  },
  "details": "## Summary\n\nAllocation of Resources Without Limits or Throttling vulnerability in `hackney_conn` in benoitc hackney allows a malicious HTTP server to exhaust client memory via an oversized or highly compressed response body. `hackney:request/5` and `hackney:body/1` return the whole response body, and nothing bounds how much the connection process buffers. Any server the client requests can trigger it.\n\n`hackney_conn:read_full_body/2` and the HTTP/2 and HTTP/3 accumulators append every chunk until the body ends. With `{auto_decompress, true}` the buffered body is then inflated in one step with `zlib:gunzip/1` or `zlib:inflate/2`, which return the whole output at once.\n\nThis issue affects hackney: from 2.0.0-beta.1 before 4.9.0.\n\n## Details\n\n**1. Unbounded accumulation.** `hackney:request/5` with a body, and `hackney:body/1` after `start_response/1`, read the response in `src/hackney_conn.erl` through `read_full_body/2`, which appends each chunk to a binary accumulator until the body ends. The HTTP/2 and HTTP/3 synchronous paths accumulate stream data the same way. No option caps the size.\n\n**2. One-step decompression.** With `{auto_decompress, true}` hackney sends `Accept-Encoding: gzip, deflate`. Once the body is complete, `maybe_decompress_body/2` dispatches on `Content-Encoding` to `decompress_gzip/1` (`zlib:gunzip/1`) or `decompress_deflate/1` (`zlib:inflate/2`). Both return the whole output at once, so the inflated size is bounded only by the compression ratio. The report measured a 1 MB gzip body inflating to 1 GB on hackney 4.8.4.\n\n## Proof of concept\n\n1. Build a gzip stream whose inflated size is 1 GB from a reused 64 KB chunk of zero bytes (deflate with window bits 31, best compression). The stream is about 1 MB on the wire.\n2. Start a TCP listener on loopback that accepts one connection, reads the request, and answers `HTTP/1.1 200 OK` with `Content-Encoding: gzip`, a `Content-Length` matching the stream, `Connection: close`, and the stream as body.\n3. From a node running a vulnerable hackney, call `hackney:request(get, Url, [], <<>>, [{auto_decompress, true}, with_body])` against that listener.\n4. Observe the returned body of 1,048,576,000 bytes and the VM memory growing by about 1.8 GB for a 1,019,197 byte response. A larger stream, or an endless body without `auto_decompress`, drives the node out of memory.\n\n## Impact\n\nA server the client requests can make the client allocate memory proportional to the body it sends, or to its decompressed size, until the node runs out of memory.\n\n## Workarounds\n\nLeave `auto_decompress` disabled (the default). Without it `hackney_conn:maybe_decompress_body/2` never inflates the body, which closes the amplification half. The uncapped raw body read has no workaround.",
  "id": "EEF-CVE-2026-97200",
  "modified": "2026-10-26T14:00:04.842482189Z",
  "published": "2026-10-26T13:49:40.392Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://github.com/benoitc/hackney/releases/tag/4.9.0"
    },
    {
      "type": "WEB",
      "url": "https://cna.erlef.org/cves/CVE-2026-97200.html"
    },
    {
      "type": "WEB",
      "url": "https://github.com/benoitc/hackney/pull/980"
    },
    {
      "type": "WEB",
      "url": "https://github.com/benoitc/hackney/commit/dc41b79339ca0c41e16d3f2dd17172bc2de855d6"
    },
    {
      "type": "FIX",
      "url": "https://github.com/benoitc/hackney/commit/493e8bf83a391548e5101792276ab3fc428fa76c"
    },
    {
      "type": "PACKAGE",
      "url": "https://hex.pm/packages/hackney"
    }
  ],
  "schema_version": "1.9.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Unbounded response body buffering and decompression in hackney"
}
View JSON API Download JSON