GHSA-J43X-5HJQ-RGXF

Vulnerability from github – Published: 2026-09-23 14:00 – Updated: 2026-09-23 14:00
VLAI
Summary
Plug: quadratic-time decoding of nested query/body parameters enables denial of service
Details

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.split_keys/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.insert_keys/3 then does one Map.put per level keyed on that growing prefix, hashing the full byte range each time, and Plug.Conn.Query.finalize_pointer/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 decode_each/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
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Hex",
        "name": "plug"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.15.0"
            },
            {
              "fixed": "1.15.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Hex",
        "name": "plug"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.16.0"
            },
            {
              "fixed": "1.16.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Hex",
        "name": "plug"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.17.0"
            },
            {
              "fixed": "1.17.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Hex",
        "name": "plug"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.18.0"
            },
            {
              "fixed": "1.18.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Hex",
        "name": "plug"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.19.0"
            },
            {
              "fixed": "1.19.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-54892"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-407"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-23T14:00:22Z",
    "nvd_published_at": "2026-06-23T13:16:43Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nPlug\u0027s 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.\n\n### Details\n\nFor a key like `a[a][a]...=1`, `Plug.Conn.Query.split_keys/6` (in `lib/plug/conn/query.ex`) builds an accumulator of `:binary.part` prefixes (`a`, `a[a]`, `a[a][a]`, \u2026) that grow ~3 bytes per level. `Plug.Conn.Query.insert_keys/3` then does one `Map.put` per level keyed on that growing prefix, hashing the full byte range each time, and `Plug.Conn.Query.finalize_pointer/2` repeats the prefix-keyed walk to materialize the structure. Total cost is `O(N\u00b2)` in nesting depth.\n\nThe same code path handles query strings, `application/x-www-form-urlencoded` bodies, and multipart field names via `Plug.Conn.Query.decode/4` and `decode_each/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\u00d7 scaling per 2\u00d7 input (16k levels \u2248 195 ms on a single scheduler).\n\n### PoC\n\n1. 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.\n2. Launch one such request per scheduler concurrently. Each pins a scheduler for minutes; legitimate traffic stalls once all schedulers are busy.\n\n### Impact\n\nA 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.\n\n### References\n\n* Introduction commit: https://github.com/elixir-plug/plug/commit/712b875d3442c765d8d37e546ffd5ad9f8afcc55\n* Patch commit: https://github.com/elixir-plug/plug/commit/b4aa8a0665ce2726a6d5af44467fb4f59595b107",
  "id": "GHSA-j43x-5hjq-rgxf",
  "modified": "2026-09-23T14:00:22Z",
  "published": "2026-09-23T14:00:22Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/elixir-plug/plug/security/advisories/GHSA-j43x-5hjq-rgxf"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54892"
    },
    {
      "type": "WEB",
      "url": "https://github.com/elixir-plug/plug/commit/9c5d37c440eaae92869eed7c014c47266744fadb"
    },
    {
      "type": "WEB",
      "url": "https://github.com/elixir-plug/plug/commit/a61124aa625d819a218fb07f90afbac8aa85eb0e"
    },
    {
      "type": "WEB",
      "url": "https://github.com/elixir-plug/plug/commit/c317d08fdcf96e17931f7419275b2b8c4bf3e951"
    },
    {
      "type": "WEB",
      "url": "https://github.com/elixir-plug/plug/commit/d4e5568392a4b29e545b91e12e87d6098f976145"
    },
    {
      "type": "WEB",
      "url": "https://github.com/elixir-plug/plug/commit/d737eb236f17e31a36290e39f9ef3cd86a1343bd"
    },
    {
      "type": "WEB",
      "url": "https://cna.erlef.org/cves/CVE-2026-54892.html"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/elixir-plug/plug"
    },
    {
      "type": "WEB",
      "url": "https://github.com/elixir-plug/plug/blob/v1.19.3/CHANGELOG.md#v1193-2026-06-23"
    },
    {
      "type": "WEB",
      "url": "https://osv.dev/vulnerability/EEF-CVE-2026-54892"
    }
  ],
  "schema_version": "1.4.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": " Plug: quadratic-time decoding of nested query/body parameters enables denial of service"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…