CVE-2026-54451: Protobuf Unbounded Recursion Depth Vulnerability
HIGHCVE-2026-54451 is a HIGH unbounded recursion depth vulnerability (CWE-674: Uncontrolled Recursion) affecting Protobuf libraries in the Hex ecosystem. The issue involves unbounded recursion depth in embedded-message decoding. Remediation is available by upgrading affected packages to version 0.16.1.
CVE-2026-54451 at a Glance
How to Fix CVE-2026-54451
To remediate this vulnerability, upgrade all affected Protobuf dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade protobuf to 0.16.1
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for protobuf
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-54451, inspect your project dependencies for Protobuf:
inspect dependencies for protobuf
Analyze the terminal output to locate any version of Protobuf in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.16.1), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-674: Uncontrolled Recursion, where the product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack. In Protobuf, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-54451 Affected Protobuf Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
protobuf
|
Hex |
≥ 0.8.0
< 0.16.1
|
0.16.1
|
References
Frequently Asked Questions
What is CVE-2026-54451?
Which Protobuf versions are affected?
What version fixes CVE-2026-54451?
Is protobuf affected?
What CWE is associated with CVE-2026-54451?
How can I check Hex dependencies for CVE-2026-54451?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-rv48-qqj5-crxg",
"modified" : "2026-07-15T17:44:28Z",
"published" : "2026-07-15T17:44:28Z",
"aliases" : [ "CVE-2026-54451" ],
"summary" : "Protobuf: Unbounded recursion depth in embedded-message decoding",
"details" : "### Summary\n\nUnbounded 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).\n\n### Details\n\n`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.\n\nThere 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.\n\nReference 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.\n\nThe 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.\n\n### PoC\n\n1. Define a self-referential schema: `defmodule Tree do use Protobuf, syntax: :proto3; field(:child, 1, type: Tree) end`.\n2. Build a wire-format body inner-to-outer: at each of `depth` levels prepend `<<0x0A, length_varint(inner_size), inner>>` (tag `0x0A` = field 1, wire type 2). Use an iolist with a running byte-size to keep generation O(depth).\n3. POST the body (a few MB at `depth = 1_000_000`) as `application/x-protobuf` to any endpoint that calls `Tree.decode/1`.\n4. The non-tail `decode(bin, type)` in `value_for_field/3` re-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.\n\n### Impact\n\nUnauthenticated, 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. \n\n## Resources\n\n* Introduction commit: https://github.com/elixir-protobuf/protobuf/commit/21ec7c5bec4fec74e10c1de0d5d1a2d8152ac5d4\n* Patch commit: https://github.com/elixir-protobuf/protobuf/commit/b8efa97790eece3d2d0e8e7c31a45ed409fe5338",
"severity" : [ {
"type" : "CVSS_V4",
"score" : "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"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Hex",
"name" : "protobuf"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0.8.0"
}, {
"fixed" : "0.16.1"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/elixir-protobuf/protobuf/security/advisories/GHSA-rv48-qqj5-crxg"
}, {
"type" : "WEB",
"url" : "https://github.com/elixir-protobuf/protobuf/commit/21ec7c5bec4fec74e10c1de0d5d1a2d8152ac5d4"
}, {
"type" : "WEB",
"url" : "https://github.com/elixir-protobuf/protobuf/commit/b8efa97790eece3d2d0e8e7c31a45ed409fe5338"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/elixir-protobuf/protobuf"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-674" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-07-15T17:44:28Z",
"nvd_published_at" : null
}
}