Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-56814

CVE-2026-56814: Plug.Parsers.MULTIPART DoS Vulnerability

CVE-2026-56814 is a denial of service vulnerability in Plug.Parsers.MULTIPART that allows attackers to exhaust system resources through malicious multipart requests. This article covers technical details, affected versions, impact, and mitigation.

Published:

CVE-2026-56814 Overview

CVE-2026-56814 is a denial of service vulnerability in Plug, the widely used specification and connection adapter library for building Elixir web applications. The flaw resides in Plug.Parsers.MULTIPART, the multipart request-body parser that handles file uploads and multipart forms. The parser fails to enforce its :length budget against all consumed resources, counting only part body bytes while ignoring part header bytes and empty-body parts. An unauthenticated remote attacker can send a single request containing many empty-body file parts, staying under the default 8,000,000 byte :length limit while creating one temporary file per part. This behavior is categorized under CWE-770: Allocation of Resources Without Limits or Throttling.

Critical Impact

Any application exposing a multipart endpoint over HTTP can be forced into inode exhaustion, disk exhaustion, and unbounded memory growth by a single unauthenticated request.

Affected Products

  • plug from 1.4.0 before 1.16.6
  • plug from 1.17.0 before 1.17.4, and from 1.18.0 before 1.18.5
  • plug from 1.19.0 before 1.19.5, and from 1.20.0 before 1.20.3

Discovery Timeline

  • 2026-07-10 - CVE-2026-56814 published to NVD
  • 2026-07-10 - Last updated in NVD database

Technical Details for CVE-2026-56814

Vulnerability Analysis

The defect lies in lib/plug/parsers/multipart.ex, specifically in the routines Plug.Parsers.MULTIPART.parse_multipart/2, parse_multipart_headers/5, parse_multipart_body/4, and parse_multipart_file/4. These functions accept the configured :length budget as an accounting parameter, but they only subtract bytes consumed by part bodies. Header bytes for each part are never counted against the budget, and any part with an empty body costs zero against the limit.

Multipart parts whose Content-Disposition header carries a non-empty filename trigger creation of a fresh temporary file through Plug.Upload. A Plug.Upload struct is retained for the full duration of the request. An attacker can therefore craft a single request containing thousands of file parts, each with valid headers but an empty body. The request stays well under the 8,000,000 byte default :length limit while allocating one temporary file and one struct per part.

Root Cause

The root cause is a missing accounting step in the parser. The :length limit was designed as a total request-size budget but was implemented as a body-bytes-only counter. Because temporary file creation is triggered per part rather than per byte, an attacker controls resource allocation independently of the byte budget.

Attack Vector

Exploitation requires only network reachability of any multipart-accepting endpoint. No authentication, user interaction, or privilege is required. A single HTTP POST with a multipart/form-data body containing many empty-body file parts is sufficient to exhaust inodes, disk space, or memory on the target host.

text
# Patch excerpt from lib/plug/parsers/multipart.ex
defp parse_multipart_headers(headers, conn, limit, opts, acc) do
+   limit = limit - headers_size(headers)
+
    case multipart_type(headers) do
      {:binary, name} ->
        {:ok, limit, body, conn} =
text
# Patch excerpt from lib/plug/conn.ex
defp read_part_headers(conn, data, length, boundary, adapter, state, opts) do
  case :plug_multipart.parse_headers(data, boundary) do
    {:ok, _headers, rest} when byte_size(data) - byte_size(rest) > length ->
-     {:error, :too_large, store_multipart(conn, {boundary, data}, adapter, state)}
+     {:error, :too_large, store_multipart(conn, {boundary, rest}, adapter, state)}

    {:ok, headers, rest} ->
      {:ok, headers, store_multipart(conn, {boundary, rest}, adapter, state)}

Source: GitHub commit 0ee8afc. The fix now deducts header size from the running limit and preserves the residual buffer on the too-large path so that skipped multiparts are also charged against the budget.

Detection Methods for CVE-2026-56814

Indicators of Compromise

  • Sudden spikes in inode consumption on filesystems backing Plug.Upload temporary directories, typically /tmp or the path from the PLUG_TMPDIR environment variable.
  • Unusually large numbers of files with names matching the plug-* temporary file pattern created within a short window.
  • HTTP POST requests with Content-Type: multipart/form-data containing hundreds or thousands of parts but small total body size.
  • BEAM VM memory growth correlated with active multipart requests but without corresponding upload throughput.

Detection Strategies

  • Inspect access logs for multipart/form-data POST requests with abnormally low Content-Length values relative to part count.
  • Instrument Plug endpoints to record part count per request and alert when a single request declares more parts than a reasonable threshold.
  • Correlate temporary file creation rate in Plug.Upload tmp directories against request rate to surface amplification.

Monitoring Recommendations

  • Monitor free inodes and free disk space on volumes hosting the Plug temporary directory, with alerting on rapid depletion.
  • Track Erlang VM process memory and process count for the web application to catch unbounded growth tied to request handling.
  • Log and rate-limit clients that submit multipart requests exceeding a defined part-count ceiling.

How to Mitigate CVE-2026-56814

Immediate Actions Required

  • Upgrade plug to a fixed release: 1.16.6, 1.17.4, 1.18.5, 1.19.5, or 1.20.3 depending on the branch in use.
  • Audit application configuration of Plug.Parsers and reduce the :length option for endpoints that do not require large uploads.
  • Restrict exposure of multipart-accepting routes behind authentication or a reverse proxy that enforces per-request part limits where feasible.

Patch Information

The fix is distributed through the elixir-plug repository. Relevant commits include 0ee8afc, 56edca2, 981597d, cae3605, df97d3f, and f7effae. See the GitHub Security Advisory GHSA-95qv-c9g9-rm63 and the Erlang Ecosystem Foundation CNA advisory for full details.

Workarounds

  • Place a reverse proxy such as NGINX in front of the Plug application and cap client_max_body_size plus the maximum number of multipart parts per request.
  • Lower the :length option passed to Plug.Parsers so that even small header-heavy requests are rejected earlier.
  • Restrict multipart routes to authenticated users to reduce the unauthenticated attack surface until the upgrade is deployed.
bash
# Update the dependency in mix.exs, then fetch and compile
# Example constraint for the 1.20.x branch:
#   {:plug, "~> 1.20.3"}

mix deps.update plug
mix deps.get
mix compile

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.