eef-cve-2026-111101

CVSS 8.7 osv_hex
Description

## Summary Allocation of Resources Without Limits or Throttling vulnerability in the HTTP/1.1 chunked body reader of mtrudel bandit allows an unauthenticated remote attacker to exhaust server memory and CPU via a request body made of many 1-byte chunks. The chunked reader in `lib/bandit/http1/socket.ex` keeps every chunk as its own list cell and binary term until `IO.iodata_to_binary/1` joins them, and nothing limits the number of chunks. The `:length` option of `read_body/2` counts only data bytes, so tiny chunks cost far more memory than their payload: 48 MB of 1-byte chunks grew one handler process to about 500 MB and took about 6 s of CPU. The route does not need to read the body, because on keep-alive connections `ensure_completed/1` drains unread bodies through the same reader. This issue affects bandit: from 0.1.0 before 1.14.0. ## Details **1. Per-chunk accumulation.** `do_read_chunked_data!` in `lib/bandit/http1/socket.ex` collects chunks as `[body | chunk]`, adding a cons cell and a binary term for every chunk. **2. Byte-only limit.** `:length` limits data bytes, not the number of chunks, so a body of `1\r\nx\r\n` chunks becomes an 8-million-element improper list before `IO.iodata_to_binary` runs. Sending 48 MB of 1-byte chunks grew the handler heap to about 500 MB and used about 6 s of CPU. The same body as one 8 MB chunk peaked at about 16 MB and took 5 ms. **3. No body read needed.** On keep-alive connections, `ensure_completed/1` drains unread bodies through the same path. Against a Plug that never calls `read_body`, the attack used about 417 MB. ## Proof of concept 1. Run Bandit with a Plug that calls `Plug.Conn.read_body(conn, length: 1_000_000, read_length: 1_000_000)`. 2. Send `POST /` with `Transfer-Encoding: chunked` and a body of 1,000,000 chunks of `1\r\nA\r\n`, followed by `0\r\n\r\n`. 3. When `read_body` returns the 1,000,000 body bytes, the handler process holds about 48 MB and BEAM memory has grown by about 55 MB, for 6 MB sent. ## Impact An unauthenticated client can make a single HTTP/1.1 request hold many times its body size in server memory (about 48 MB for a 1 MB body in the reporter's test), and keep CPU busy while the chunks are joined. This affects any Bandit server that accepts HTTP/1.1 requests, whether or not its routes read the body. ## Workarounds From 0.7.0, a server whose clients and proxies all speak HTTP/2 can disable HTTP/1 with `http_1_options: [enabled: false]`, so that the vulnerable chunked body reader never runs.

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-111101.json"
      },
      "package": {
        "ecosystem": "Hex",
        "name": "bandit",
        "purl": "pkg:hex/bandit"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.1.0"
            },
            {
              "fixed": "1.14.0"
            }
          ],
          "type": "SEMVER"
        }
      ],
      "versions": [
        "0.1.0",
        "0.1.1",
        "0.2.0",
        "0.2.1",
        "0.2.2",
        "0.2.3",
        "0.3.2",
        "0.3.3",
        "0.3.4",
        "0.3.5",
        "0.3.6",
        "0.3.7",
        "0.3.8",
        "0.3.9",
        "0.4.0",
        "0.4.1",
        "0.4.10",
        "0.4.2",
        "0.4.3",
        "0.4.4",
        "0.4.5",
        "0.4.6",
        "0.4.7",
        "0.4.8",
        "0.4.9",
        "0.5.0",
        "0.5.1",
        "0.5.10",
        "0.5.11",
        "0.5.2",
        "0.5.3",
        "0.5.4",
        "0.5.5",
        "0.5.6",
        "0.5.7",
        "0.5.8",
        "0.5.9",
        "0.6.0",
        "0.6.1",
        "0.6.10",
        "0.6.11",
        "0.6.2",
        "0.6.3",
        "0.6.4",
        "0.6.5",
        "0.6.6",
        "0.6.7",
        "0.6.8",
        "0.6.9",
        "0.7.0",
        "0.7.1",
        "0.7.2",
        "0.7.3",
        "0.7.4",
        "0.7.5",
        "0.7.6",
        "0.7.7",
        "1.0.0",
        "1.0.0-pre.1",
        "1.0.0-pre.10",
        "1.0.0-pre.11",
        "1.0.0-pre.12",
        "1.0.0-pre.13",
        "1.0.0-pre.14",
        "1.0.0-pre.15",
        "1.0.0-pre.16",
        "1.0.0-pre.17",
        "1.0.0-pre.18",
        "1.0.0-pre.2",
        "1.0.0-pre.3",
        "1.0.0-pre.4",
        "1.0.0-pre.5",
        "1.0.0-pre.6",
        "1.0.0-pre.7",
        "1.0.0-pre.8",
        "1.0.0-pre.9",
        "1.1.0",
        "1.1.1",
        "1.1.2",
        "1.1.3",
        "1.10.0",
        "1.10.1",
        "1.10.2",
        "1.10.3",
        "1.10.4",
        "1.11.0",
        "1.11.1",
        "1.12.0",
        "1.12.1",
        "1.12.2",
        "1.12.3",
        "1.12.4",
        "1.12.5",
        "1.13.0",
        "1.13.1",
        "1.2.0",
        "1.2.1",
        "1.2.2",
        "1.2.3",
        "1.3.0",
        "1.4.0",
        "1.4.1",
        "1.4.2",
        "1.5.0",
        "1.5.1",
        "1.5.2",
        "1.5.3",
        "1.5.4",
        "1.5.5",
        "1.5.6",
        "1.5.7",
        "1.6.0",
        "1.6.1",
        "1.6.10",
        "1.6.11",
        "1.6.2",
        "1.6.3",
        "1.6.4",
        "1.6.5",
        "1.6.6",
        "1.6.7",
        "1.6.8",
        "1.6.9",
        "1.7.0",
        "1.8.0",
        "1.9.0"
      ]
    },
    {
      "database_specific": {
        "source": "https://cna.erlef.org/osv/EEF-CVE-2026-111101.json"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "7201270c34b90f6c9e15c0386c2bb802c0c72ab4"
            },
            {
              "fixed": "220b9dfd27f9a21305be2afc75cbe585ddc24e7a"
            }
          ],
          "repo": "https://github.com/mtrudel/bandit",
          "type": "GIT"
        }
      ],
      "versions": [
        "1.13.1",
        "1.13.0",
        "1.12.5",
        "1.12.4",
        "1.12.3",
        "1.12.1",
        "1.12.0",
        "1.11.1",
        "1.11.0",
        "1.10.4",
        "1.10.3",
        "1.10.2",
        "1.10.1",
        "1.10.0",
        "1.9.0",
        "1.8.0",
        "1.7.0",
        "1.6.11",
        "1.6.10",
        "1.6.9",
        "1.6.8",
        "1.6.7",
        "1.6.6",
        "1.6.5",
        "1.6.4",
        "1.6.3",
        "1.6.2",
        "1.6.1",
        "1.6.0",
        "1.5.7",
        "1.5.6",
        "1.5.5",
        "1.5.4",
        "1.5.3",
        "1.5.2",
        "1.5.1",
        "1.5.0",
        "1.4.2",
        "1.4.1",
        "1.4.0",
        "1.3.0",
        "1.2.3",
        "1.2.0",
        "1.1.3",
        "1.1.2",
        "1.1.1",
        "1.1.0",
        "1.0.0",
        "1.0.0-pre.18",
        "1.0.0-pre.17",
        "1.0.0-pre.16",
        "1.0.0-pre.15",
        "1.0.0-pre.14",
        "1.0.0-pre.13",
        "1.0.0-pre.12",
        "1.0.0-pre.11",
        "1.0.0-pre.10",
        "1.0.0-pre.9",
        "1.0.0-pre.8",
        "1.0.0-pre.7",
        "1.0.0-pre.6",
        "1.0.0-pre.5",
        "1.0.0-pre.4",
        "1.0.0-pre.3",
        "1.0.0-pre.2",
        "1.0.0-pre.1",
        "0.7.7",
        "0.7.6",
        "0.7.5",
        "0.7.4",
        "0.7.3",
        "0.7.2",
        "0.7.1",
        "0.7.0",
        "0.6.11",
        "0.6.10",
        "0.6.9",
        "0.6.8",
        "0.6.7",
        "0.6.6",
        "0.6.5",
        "0.6.4",
        "0.6.3",
        "0.6.2",
        "0.6.1",
        "0.6.0",
        "0.5.11",
        "0.5.10",
        "0.5.9",
        "0.5.8",
        "0.5.7",
        "0.5.6",
        "0.5.5",
        "0.5.4",
        "0.5.3",
        "0.5.2",
        "0.5.1",
        "0.5.0",
        "0.4.10",
        "0.4.9",
        "0.4.8",
        "0.4.7",
        "0.4.6",
        "0.4.5",
        "0.4.4",
        "0.4.3",
        "0.4.2",
        "0.4.1",
        "0.4.0",
        "0.3.9",
        "0.3.8",
        "0.3.7",
        "0.3.6",
        "0.3.5",
        "0.3.4",
        "0.3.3",
        "0.3.2",
        "0.3.1",
        "0.3.0",
        "0.2.3",
        "0.2.2",
        "0.2.1",
        "0.2.0",
        "0.1.1",
        "0.1.0"
      ]
    }
  ],
  "aliases": [
    "CVE-2026-111101",
    "GHSA-jwh3-j29h-qfmw"
  ],
  "credits": [
    {
      "name": "Peter Ullrich",
      "type": "REPORTER"
    },
    {
      "name": "Mat Trudel",
      "type": "REMEDIATION_DEVELOPER"
    },
    {
      "name": "Jonatan Männchen / EEF",
      "type": "ANALYST"
    }
  ],
  "database_specific": {
    "capec_ids": [
      "CAPEC-130"
    ],
    "cpe_ids": [
      "cpe:2.3:a:mtrudel:bandit:*:*:*:*:*:*:*:*"
    ],
    "cwe_ids": [
      "CWE-770"
    ]
  },
  "details": "## Summary\n\nAllocation of Resources Without Limits or Throttling vulnerability in the HTTP/1.1 chunked body reader of mtrudel bandit allows an unauthenticated remote attacker to exhaust server memory and CPU via a request body made of many 1-byte chunks.\n\nThe chunked reader in `lib/bandit/http1/socket.ex` keeps every chunk as its own list cell and binary term until `IO.iodata_to_binary/1` joins them, and nothing limits the number of chunks. The `:length` option of `read_body/2` counts only data bytes, so tiny chunks cost far more memory than their payload: 48 MB of 1-byte chunks grew one handler process to about 500 MB and took about 6 s of CPU. The route does not need to read the body, because on keep-alive connections `ensure_completed/1` drains unread bodies through the same reader.\n\nThis issue affects bandit: from 0.1.0 before 1.14.0.\n\n## Details\n\n**1. Per-chunk accumulation.** `do_read_chunked_data!` in `lib/bandit/http1/socket.ex` collects chunks as `[body | chunk]`, adding a cons cell and a binary term for every chunk.\n\n**2. Byte-only limit.** `:length` limits data bytes, not the number of chunks, so a body of `1\\r\\nx\\r\\n` chunks becomes an 8-million-element improper list before `IO.iodata_to_binary` runs. Sending 48 MB of 1-byte chunks grew the handler heap to about 500 MB and used about 6 s of CPU. The same body as one 8 MB chunk peaked at about 16 MB and took 5 ms.\n\n**3. No body read needed.** On keep-alive connections, `ensure_completed/1` drains unread bodies through the same path. Against a Plug that never calls `read_body`, the attack used about 417 MB.\n\n## Proof of concept\n\n1. Run Bandit with a Plug that calls `Plug.Conn.read_body(conn, length: 1_000_000, read_length: 1_000_000)`.\n2. Send `POST /` with `Transfer-Encoding: chunked` and a body of 1,000,000 chunks of `1\\r\\nA\\r\\n`, followed by `0\\r\\n\\r\\n`.\n3. When `read_body` returns the 1,000,000 body bytes, the handler process holds about 48 MB and BEAM memory has grown by about 55 MB, for 6 MB sent.\n\n## Impact\n\nAn unauthenticated client can make a single HTTP/1.1 request hold many times its body size in server memory (about 48 MB for a 1 MB body in the reporter's test), and keep CPU busy while the chunks are joined. This affects any Bandit server that accepts HTTP/1.1 requests, whether or not its routes read the body.\n\n## Workarounds\n\nFrom 0.7.0, a server whose clients and proxies all speak HTTP/2 can disable HTTP/1 with `http_1_options: [enabled: false]`, so that the vulnerable chunked body reader never runs.",
  "id": "EEF-CVE-2026-111101",
  "modified": "2026-10-26T13:56:06.466616787Z",
  "published": "2026-10-26T13:31:48.184Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://github.com/mtrudel/bandit/security/advisories/GHSA-jwh3-j29h-qfmw"
    },
    {
      "type": "WEB",
      "url": "https://cna.erlef.org/cves/CVE-2026-111101.html"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mtrudel/bandit/commit/7201270c34b90f6c9e15c0386c2bb802c0c72ab4"
    },
    {
      "type": "FIX",
      "url": "https://github.com/mtrudel/bandit/commit/220b9dfd27f9a21305be2afc75cbe585ddc24e7a"
    },
    {
      "type": "PACKAGE",
      "url": "https://hex.pm/packages/bandit"
    }
  ],
  "schema_version": "1.9.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "HTTP/1.1 chunked request bodies made of 1-byte chunks amplify memory use in Bandit"
}
View JSON API Download JSON