Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessIdentify endpoint decoding recursive protobuf schema
-
DeliveryCraft tiny deeply-nested wire-format body
-
ExploitPOST as application/x-protobuf
-
ExecutionDecoder recurses once per nesting level
-
PersistMemory/CPU/scheduler exhausted
-
ImpactNode taken offline (DoS)
Vulnerability Assessment
| Weakness |
CWE
ASVS 5.0
V15 - Secure Coding and Architecture Recursion depth limits
|
| Exploitation Conditions | Exploitable only when a network-reachable service built on the Elixir/Erlang Hex |
| Impact | This is a legitimate, well-substantiated availability threat rather than an inflated high-CVSS score, but its real-world reach is narrower than the 8.2 base score suggests. The vendor CVSS 4.0 vector (AV:N/AC:L/AT:P/PR:N/UI:N) shows a network-reachable, low-complexity, unauthenticated flaw whose only impact is availability (VC:N/VI:N/VA:H) - a pure denial of service, consistent with CWE-674 (uncontrolled recursion). The single most important signal is AT:P (Attack Requirements: Present): exploitation is not universal against every service using this library - it requires the target to decode untrusted input into a self-referential or cyclic protobuf message type. Publicly available PoC code raises operational risk (the advisory contains a step-by-step exploit and both the introducing and fixing commits are public), but this is exploit availability, NOT active exploitation - the CVE is not in CISA KEV and no EPSS score is provided in the input, so there is no evidence of exploitation in the wild. No confidentiality or integrity impact exists, so this cannot be chained to code execution or data theft; the worst outcome is node/service unavailability. Net priority: patch promptly on any Elixir/Erlang service that decodes attacker-influenced protobuf into recursive schemas, but treat lower-risk than an RCE. Note the vector is CVSS 4.0 only - no 3.1 vector was supplied by the vendor. |
| Exploit ScenarioDerived | An attacker identifies an Elixir/Erlang HTTP endpoint that decodes protobuf bodies into a self-referential message type (e.g. a comment-thread, org-chart, file-tree, or AST schema). They POST a small (few KB-few MB) application/x-protobuf body that nests an embedded field hundreds of thousands to millions of levels deep, forcing the decoder to recurse once per level and exhaust memory and CPU on a scheduler. A handful of such concurrent requests takes the BEAM node offline; a public step-by-step PoC exists in the GHSA advisory. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv2 – Sep 17, 2026
Unbounded recursion in the Elixir protobuf Hex package (versions >= 0.8.0, < 0.16.1) lets unauthenticated remote attackers take down any service that decodes untrusted protobuf bytes into a self-referential or cyclic message type, because each nested embedded message is decoded with a non-tail recursive call that retains a live stack and heap frame on the BEAM. A body of only a few KB to a few MB can nest an embedded field hundreds of thousands to millions of levels deep, consuming hundreds of MB of memory and seconds of CPU per request and pinning a scheduler, so a handful of concurrent requests can starve and crash the node. Publicly available exploit code exists, and the vendor has released a patch in 0.16.1 that enforces a configurable :max_nesting_depth defaulting to 100, matching Google's C++/Java reference implementations; exploitation is conditional on the target schema actually being recursive (reflected as CVSS 4.0 AT:P), so services decoding only flat message types are not affected despite the 8.2 base score.
Earlier versions of this analysis (1)
Denial of service in the Elixir/Erlang Hex package protobuf (>= 0.8.0, < 0.16.1) allows an unauthenticated remote attacker to crash any service that decodes untrusted protobuf messages into a self-referential or cyclic message type. Because Protobuf.Decoder performs unbounded, non-tail recursion over embedded message fields, a small request body (a few KB to a few MB) can nest a field hundreds of thousands to millions of levels deep, forcing the BEAM to retain one stack/heap frame per level until it exhausts memory and pins a scheduler; a handful of concurrent requests take the node offline. This is a request-amplification DoS with a publicly available proof-of-concept, but no CISA KEV listing and no evidence of active exploitation; no CVSS or EPSS score is provided in the source data.
RemediationAI
Upgrade to protobuf 0.16.1, the vendor-released fixed version (release notes: https://github.com/elixir-protobuf/protobuf/releases/tag/v0.16.1; advisory: https://github.com/elixir-protobuf/protobuf/security/advisories/GHSA-rv48-qqj5-crxg), which threads a depth counter through decoding and raises Protobuf.DecodeError once nesting exceeds a limit defaulting to 100; after upgrading, Protobuf.decode/3 accepts a :max_nesting_depth option so you can lower the threshold for schemas whose realistic nesting is shallow (too-low values will reject legitimate deeply nested data, so set it above your observed maximum). If upgrading is not immediately possible, compensating controls are limited because the request body can be as small as a few KB, so blanket HTTP body-size limits are insufficient on their own; more effective options are to avoid or restructure self-referential and cyclic schemas (flattening a recursive Tree into a repeated/adjacency representation eliminates the recursion entirely, at the cost of application changes), to pre-scan or proxy-reject length-delimited payloads whose nesting depth exceeds ~100 before handing them to the library (adds parsing CPU per request), to restrict which endpoints accept application/x-protobuf from untrusted clients and rate-limit per connection (reduces but does not remove the amplification risk), and to isolate protobuf-decoding workloads so a crashed node does not take unrelated services down. Note that the fix commits 21ec7c5bec4fec74e10c1de0d5d1a2d8152ac5d4 and b8efa97790eece3d2d0e8e7c31a45ed409fe5338 implement the upstream change, while 0.16.1 is the version to track in dependency manifests; there is no evidence of active exploitation in CISA KEV, but publicly available exploit code exists and unauthenticated remote exploitation is confirmed by the vendor advisory.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
The issue is CWE-674 (Uncontrolled Recursion) in the pure-Elixir protobuf wire-format decoder shipped in the Hex package protobuf (CPE pkg:erlang/protobuf). Protocol Buffers encodes an embedded message field as wire type 2 (length-delimited): a one-byte field tag plus a varint length prefix followed by the raw sub-message bytes. Protobuf.Decoder.value_for_field/3 handles that embedded?: true branch (lib/protobuf/decoder.ex:218-243) by calling decode(bin, type) recursively, which re-enters build_message -> handle_value -> value_for_field. The recursive call is not in tail position, so every level keeps a live frame; nothing in the decoder tracked or bounded nesting depth, and each additional attacker-chosen level costs only a byte of tag plus a varint, giving an extreme amplification ratio between payload size and recursion depth. On the BEAM, deep recursion and the resulting GC pressure run inside an Erlang process on a scheduler, so memory exhaustion and scheduler pinning translate directly into cluster-wide unavailability rather than a clean per-request failure. Google's C++ and Java implementations cap nesting at 100 precisely for this reason; the Elixir decoder enforced no comparable bound before the fix. The patched code threads a {current_depth, max_nesting_depth} pair through decode/3, build_message, handle_value and value_for_field, raising Protobuf.DecodeError past the limit (default 100) and exposing :max_nesting_depth as a per-call option.
Know when Elixir gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
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
Remote, unauthenticated, low-complexity request causes availability-only impact; CVSS 3.1 lacks an attack-requirement metric so the self-referential-schema precondition is not separately captured (base 7.5).
Primary rating from Vendor (https://github.com/elixir-protobuf/protobuf).
CVSS VectorVendor: https://github.com/elixir-protobuf/protobuf
Lifecycle Timeline
3DescriptionCVE.org
Summary
Unbounded recursion depth in Protobuf.Decoder (Hex package protobuf, versions >= 0.8.0, < 0.16.1) lets an unauthenticated attacker crash any service that decodes untrusted protobuf messages whose schema contains a self-referential or cyclic message type. A small request body (a few KB to a few MB) that nests an embedded field hundreds of thousands to millions of levels deep forces the BEAM to recurse once per level, exhausting memory and pinning a scheduler. A handful of such requests can take the node offline (a request-amplification denial of service).
Details
Protobuf.Decoder.value_for_field/3 handles embedded message fields in its embedded?: true branch at lib/protobuf/decoder.ex:218-243. For an embedded field it calls decode(bin, type) recursively, which re-enters build_message → handle_value → value_for_field. The recursive call is not in tail position (its result is consumed by the surrounding decode after it returns), so every nesting level retains a live frame on the process stack and heap.
There is no recursion-depth counter anywhere in the decoder. For any schema with a self-referential message type (e.g. message Tree { Tree child = 1; }, a common shape for comment threads, org charts, file trees, and ASTs) or any cycle of message types, the attacker controls the nesting depth entirely through the input bytes. Each additional level costs only a 1-byte field tag plus a varint length prefix, so depth grows roughly inversely with payload size: a tiny body buys an enormous recursion depth.
Reference protobuf implementations (Google's C++, Java, etc.) cap recursion at 100 specifically to prevent this. The Elixir decoder enforces no comparable bound, so the recursion continues until the process exhausts memory, blows the stack, or starves the scheduler doing GC over the deep structure.
The fix threads a depth counter through decode / build_message / handle_value / value_for_field (or holds it in the process dictionary for the duration of the top-level decode) and raises Protobuf.DecodeError once it exceeds a configurable limit, defaulting to 100 to match the reference implementations.
PoC
- Define a self-referential schema:
defmodule Tree do use Protobuf, syntax: :proto3; field(:child, 1, type: Tree) end. - Build a wire-format body inner-to-outer: at each of
depthlevels prepend<<0x0A, length_varint(inner_size), inner>>(tag0x0A= field 1, wire type 2). Use an iolist with a running byte-size to keep generation O(depth). - POST the body (a few MB at
depth = 1_000_000) asapplication/x-protobufto any endpoint that callsTree.decode/1. - The non-tail
decode(bin, type)invalue_for_field/3re-enters once per nesting level, accumulating a frame per level. The decode burns seconds of CPU and hundreds of MB on the victim node; a few concurrent requests exhaust it.
Impact
Unauthenticated, network-reachable request-amplification denial of service against any service that decodes attacker-influenced protobuf bytes into a self-referential or cyclic message type. A single small request can consume seconds of CPU and hundreds of MB of memory on the victim; a few concurrent requests can take the node offline.
Resources
- Introduction commit: https://github.com/elixir-protobuf/protobuf/commit/21ec7c5bec4fec74e10c1de0d5d1a2d8152ac5d4
- Patch commit: https://github.com/elixir-protobuf/protobuf/commit/b8efa97790eece3d2d0e8e7c31a45ed409fe5338
Executive ViewAI
A high-severity denial-of-service flaw in the Elixir protobuf library (versions 0.8.0 through 0.16.0) lets a small, specially crafted message exhaust memory and CPU on any Elixir or Erlang service that decodes untrusted protobuf data into a self-referential or cyclic message schema, potentially crashing an entire node with only a few concurrent requests. Because protobuf decoding sits on core, often customer-facing request paths, a successful attack can produce prolonged outages and cascading failures across dependent applications and downstream consumers. With publicly available exploit code and a vendor fix already released in 0.16.1, this is a near-term remediation priority for teams running the library in production.
Apply vendor patch.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Denial of Service attacks render applications or systems unavailable by overwhelming resources or triggering failure conditions.
Improper JWT signature verification in Dashbit's nimble_zta (0.1.2 up to but not including 0.1.3) lets an unauthenticate
Session-swapping authentication bypass in the Elixir library AshAuthentication (versions 4.10.0 before 4.15.0 and 5.0.0-
Authentication bypass in the Elixir library ash_authentication lets an attacker who operates one federated identity-prov
Account takeover in AshAuthentication (Elixir/Ash) 4.14.0 through 4.14.x and 5.0.0-rc.10 through 5.0.0-rc.13 lets unauth
Server-Side Request Forgery protection bypass in the Elixir safeurl library (versions 0.1.0 and later) allows unauthenti
Unauthenticated remote CPU exhaustion in mtrudel Bandit's HTTP/2 server (versions before 1.14.0) is achievable by holdin
Unbounded per-connection memory and CPU growth in the Elixir Bandit HTTP/2 server (0.3.6 up to 1.14.0) lets an unauthent
Unauthenticated remote denial of service in the Elixir HTTP server Bandit (mtrudel/bandit) from 0.1.0 before 1.14.0 lets
Unauthenticated remote attackers can consume disproportionate server CPU on Bandit (mtrudel/bandit, Elixir/Erlang) by se
Memory-exhaustion denial of service in the elixir-protobuf library (protobuf) from 0.8.0 onward allows an unauthenticate
Atom table exhaustion in the Ash framework (Elixir) allows an unauthenticated remote attacker to crash a BEAM node by su
Ciphertext tampering in the Cloak Elixir encryption library (danielberkompas/cloak, all versions from 0.1.0-pre onward)
EUVD-2026-82368
GHSA-rv48-qqj5-crxg
NVD
CVE.org
EPSS
Exploit-DB