An unauthenticated remote attacker can cause a crash of the decoding process by providing a deeply nested JSON document. This occurs when an application decodes attacker-supplied JSON into a schema containing a self-referential or cyclic message type using the functions `Protobuf.JSON.decode/3`, `Protobuf.JSON.decode!/3`, or `Protobuf.JSON.from decoded/3`.
In `lib/protobuf/json/decode.ex`, the `embedded-message` clause of the `decode singular/3` function recurses into `internal from json data/3` for each nesting level without incrementing or verifying the decoder's depth counter. While the `increase depth and maybe throw/1` guard exists, it only applies to `Google.Protobuf.ListValue` and `Google.Protobuf.Struct` clauses, rendering the `recursion limit` option ineffective for user-defined message types. Consequently, each nesting level allocates a stack frame and heap objects, allowing a sufficiently deep document to exhaust the memory of the decoding process and crash it. If the BEAM `max heap size` process flag is set to unlimited, concurrent requests may exhaust the memory of the entire node.