protobuf β json_format.ParseDict() Uncontrolled Recursion (PoC)
Repo: MBM7/protobuf-parsedicts-recursion-poc
Status: Responsible disclosure β submitted to Huntr
Severity: High / CWE-674
Package: protobuf (PyPI) β google.protobuf
Summary
A 7.4 KB crafted JSON payload with 200 nesting levels crashes any Python
server calling ParseDict() with a RecursionError β unhandled, terminates
the process.
| Payload size | Depth | Result |
|---|---|---|
| 7,443 bytes | 200 | RecursionError β |
| 9,293 bytes | 250 | RecursionError β |
Root Cause
google/protobuf/json_format.py, _ConvertMessage():
def _ConvertMessage(value, message, path):
for field_name, field_value in value.items():
...
_ConvertMessage(field_value, sub_message, path) # β no depth check
ParseDict() β _ConvertMessage() recurses once per nesting level
with no depth limit. Compare to the binary parser which has
DEFAULT_RECURSION_LIMIT = 100.
Asymmetry
| Parser | Depth limit |
|---|---|
ParseFromString() (binary) |
DEFAULT_RECURSION_LIMIT = 100 β
|
ParseDict() (JSONβproto) |
NONE β |
MessageToJson() |
NONE β |
MessageToDict() |
NONE β |
Attack scenario
# Server receives JSON from user, converts to proto:
user_json = json.loads(request.body)
proto_msg = MyMessage()
ParseDict(user_json, proto_msg) # β CRASH at depth 200
A 7.4 KB JSON payload with 200 nesting levels crashes the Python process.
Reproduce
pip install protobuf
python poc_protobuf_recursive_json.py
Expected:
Nesting depth : 200 levels
JSON payload : 7,443 bytes
Result : RecursionError β server CRASH β
Suggested Fix
def _ConvertMessage(value, message, path, depth=0):
if depth > _MAX_RECURSION_DEPTH: # e.g. 100, matching binary parser
raise ParseError('Message too deeply nested')
for field_name, field_value in value.items():
...
_ConvertMessage(field_value, sub_message, path, depth + 1)
Environment
| Package | Version |
|---|---|
| protobuf | 5.29.6 |
| Python | 3.12 |
Inference Providers NEW
This model isn't deployed by any Inference Provider. π Ask for provider support