Externally-Generated Error Message Containing Sensitive Information vulnerability in plugcrypto in elixir-plug plugcrypto allows an unauthenticated remote attacker to expose the secret key base through application logs via a wrong-typed argument. Every public function in Plug.Crypto validates argument types in a function-head guard. A failed guard makes the Erlang VM raise FunctionClauseError with the actual argument values in the top stack frame, so the secret key base, a derived key, or the value an API key is compared against lands in that frame. The library's rescue blocks and Plug.Crypto.pruneargsfromstacktrace/1 only reach exceptions raised inside a function body, so they never see a guard failure. Plug.Cowboy and Bandit write the frame to the error log and attach it as crashreason Logger metadata, which error trackers forward.
Two entry points take request data. Plug.Crypto.verify/4 exposes the secret key base when the token is neither a binary nor nil, which Phoenix.Token.verify/4 reaches because it forwards the token unguarded. Plug.Crypto.securecompare/2 exposes the other operand when one side is not a binary, as happens when a missing request header yields nil. Reading the leaked value needs separate access to the logs or the error tracker, so the request alone does not disclose the secret to the attacker.
This issue affects plug: from 1.6.3 before 1.7.0; plugcrypto: from 1.0.0 before 2.2.1.
Improper Neutralization of Parameter/Argument Delimiters vulnerability in elixir-plug plug allows an attacker to inject or override HTTP cookie attributes.
The Plug.Conn.Cookies.encode/2 function in lib/plug/conn/cookies.ex builds the Set-Cookie response header by interpolating the cookie value and its path, domain, samesite, and extra attributes directly into the header without neutralizing the ; delimiter that separates cookie attributes.
An application that places attacker-controlled data into a cookie value or attribute (for example via Plug.Conn.putrespcookie/4 when reflecting a username or preference) lets an attacker inject a ; to append or override cookie attributes (such as Domain and Path scope, or dropping the Secure and HttpOnly flags), enabling cookie tossing and session fixation. Carriage return, line feed, and null bytes are rejected by Plug.Conn header validation, so HTTP response splitting is not possible, but attribute injection through ; is not prevented.
This issue affects plug: from 0.1.0 before 1.16.6, from 1.17.0 before 1.17.4, from 1.18.0 before 1.18.5, from 1.19.1 before 1.19.5, and from 1.20.0 before 1.20.3.
Plug.Parsers.MULTIPART, the multipart request-body parser used to handle file uploads and multipart forms, does not enforce its :length budget against all consumed resources, allowing an unauthenticated remote attacker to cause denial of service. The parser charges the :length limit only for part body bytes; part header bytes are never counted, and a part with an empty body costs zero.
Because every part whose Content-Disposition carries a non-empty filename creates a fresh temporary file (via Plug.Upload) and retains a Plug.Upload struct for the duration of the request, an attacker can send a single request composed of many empty-body file parts. Such a request stays well under the configured :length limit (8,000,000 bytes by default) while creating one temporary file per part, leading to inode and disk exhaustion and unbounded memory growth. Any application using Plug.Parsers with the :multipart parser is affected, and no authentication is required, only reachability of a multipart endpoint over HTTP.
This vulnerability is associated with program files lib/plug/parsers/multipart.ex and program routines Plug.Parsers.MULTIPART.parsemultipart/2, Plug.Parsers.MULTIPART.parsemultipartheaders/5, Plug.Parsers.MULTIPART.parsemultipartbody/4, and Plug.Parsers.MULTIPART.parsemultipartfile/4.
This issue affects plug: from 1.4.0-rc.0 before 1.16.6, from 1.17.0 before 1.17.4, from 1.18.0 before 1.18.5, from 1.19.1 before 1.19.5, and from 1.20.0 before 1.20.3.
Summary
Plug's nested-parameter decoder (Plug.Conn.Query) parses URL-encoded keys in time quadratic in their bracket-nesting depth. Any unauthenticated remote attacker that can reach a Plug-based HTTP endpoint can pin a BEAM scheduler for minutes with a single small request.
Details
For a key like a[a][a]...=1, Plug.Conn.Query.splitkeys/6 (in lib/plug/conn/query.ex) builds an accumulator of :binary.part prefixes (a, a[a], a[a][a], …) that grow ~3 bytes per level. Plug.Conn.Query.insertkeys/3 then does one Map.put per level keyed on that growing prefix, hashing the full byte range each time, and Plug.Conn.Query.finalizepointer/2 repeats the prefix-keyed walk to materialize the structure. Total cost is O(N²) in nesting depth.
The same code path handles query strings, application/x-www-form-urlencoded bodies, and multipart field names via Plug.Conn.Query.decode/4 and decodeeach/2. The default Plug.Parsers.URLENCODED cap is 1 MB (~333,000 nesting levels), but Plug.Parsers accepts urlencoded payloads up to its overall body limit (20 MB by default), so an attacker can scale the per-request work well beyond the urlencoded-specific cap. The decoder shows ~4× scaling per 2× input (16k levels ≈ 195 ms on a single scheduler).
PoC
1. POST a[a][a]...[a]=1 as application/x-www-form-urlencoded to any endpoint of a Plug-based app. Even at the 1 MB urlencoded-parser default the payload carries ~333,000 nesting levels; with the broader Plug.Parsers body limit (20 MB default) a single request can carry millions. 2. Launch one such request per scheduler concurrently. Each pins a scheduler for minutes; legitimate traffic stalls once all schedulers are busy.
Impact
A single low-bandwidth sender can render any internet-reachable Plug-based service (most Phoenix and standalone Elixir/Erlang web stacks) unresponsive. No credentials, specific endpoint, or prior knowledge of the application is required.
References
Introduction commit: https://github.com/elixir-plug/plug/commit/712b875d3442c765d8d37e546ffd5ad9f8afcc55 Patch commit: https://github.com/elixir-plug/plug/commit/b4aa8a0665ce2726a6d5af44467fb4f59595b107
Summary
An Allocation of Resources Without Limits or Throttling vulnerability in Plug.Conn.readpartheaders/2 allows an unauthenticated attacker to exhaust server memory by sending a crafted multipart/form-data request, causing a denial of service.
Details
Plug.Conn.readpartheaders/2 in lib/plug/conn.ex does not obey its :length parameter. There is no upper bound on the size of the accumulated buffer. By contrast, the sibling function readpartbody has an explicit bytesize(acc) > length guard that stops accumulation once a limit is reached. No such guard exists in readpartheaders.
Impact
This is a denial-of-service vulnerability. Any application using Plug.Parsers with the :multipart parser, or calling Plug.Conn.readpartheaders/2 directly, is affected. An unauthenticated remote attacker can trigger the issue by sending crafted HTTP requests with no special privileges.
References
Intro Commit: https://github.com/elixir-plug/plug/commit/c52b2f32c90bccd718202bafccb5f95594e30183 Patch Commit: https://github.com/elixir-plug/plug/commit/d878b42efea9f12b243dc3e362a2ed048a798203