CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-0994

Recursive Hell: Breaking Python Protobuf with Nested 'Any' Messages

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 23, 2026·5 min read·467 visits

Executive Summary (TL;DR)

The Python implementation of Protocol Buffers contained a critical oversight in how it parsed 'Well-Known Types' nested inside `google.protobuf.Any` messages. By recursively nesting `Any` messages, an attacker could bypass the `max_recursion_depth` check entirely. This allows a relatively small JSON payload to trigger an infinite recursion loop in the parsing logic, hitting the Python interpreter's stack limit and crashing the application (DoS).

A logic flaw in Google's Python Protobuf implementation allows attackers to bypass recursion limits using nested 'Any' types, leading to a Denial of Service via stack exhaustion.

The Hook: The Russian Doll of Death

Protocol Buffers (Protobuf) are the lingua franca of modern microservices, acting as the efficient, binary glue holding together gRPC architectures. But sometimes, you need flexibility. Enter the google.protobuf.Any type—a polymorphic feature that lets you embed messages without defining their type upfront. It's effectively a void* for your schema.

While powerful, dynamic typing in a serialization format is a notorious minefield. The vulnerability we are looking at today, CVE-2026-0994, is a classic example of what happens when you trust your own "Well-Known Types" (WKT) a little too much.

The concept is simple: developers set a max_recursion_depth to prevent stack overflows. It's the bouncer at the club ensuring things don't get too rowdy. But in version 33.0+, the Protobuf parser inadvertently gave Any messages a VIP pass, allowing them to skip the bouncer entirely. This means an attacker can hand the server a JSON object that looks small but unpacks into a stack-crushing infinite loop.

The Flaw: Skipping the Checkpoint

To understand the bug, you have to look at google/protobuf/json_format.py. When the parser encounters a message, it typically calls ConvertMessage(), a function that dutifully increments a recursion counter, checks if it hits the limit, and then proceeds. So far, so good.

However, the handling for Any messages contained a fatal optimization. When the parser unpacked an Any message, it checked if the inner content was a "Well-Known Type" (like Struct, Duration, or interestingly, another Any). If it was, the code used Python's operator.methodcaller to invoke the specific handler for that type directly.

This direct invocation was the critical failure. By jumping straight to the handler logic, the code completely bypassed the ConvertMessage() gateway. Consequently, the recursion depth counter was never incremented for that nesting level. It was effectively a "free move" in the recursion game. By chaining these free moves together, you could go as deep as you wanted, regardless of the security settings.

The Code: The Smoking Gun

Let's look at the diff. It's a textbook example of how a small helper function usage can undermine security guarantees.

In the vulnerable code, methodcaller is used to dispatch the call. Note the lack of self.ConvertMessage:

# VULNERABLE CODE
elif full_name in _WKTJSONMETHODS:
  methodcaller(
      _WKTJSONMETHODS[full_name][1],
      value['value'],
      sub_message,
      '{0}.value'.format(path),
  )(self)

The fix, applied in PR #25239, forces the logic back through the main conversion pipeline. This ensures that every layer of the onion is counted against the quota:

# PATCHED CODE
elif full_name in _WKTJSONMETHODS:
  # For well-known types (including nested Any), use ConvertMessage
  # to ensure recursion depth is properly tracked
  self.ConvertMessage(
      value['value'], 
      sub_message, 
      '{0}.value'.format(path)
  )

By routing the call back through self.ConvertMessage, the _recursion_depth check is triggered before the nested content is processed. If _recursion_depth exceeds the limit, it throws a ParseError immediately, rather than letting the Python interpreter crash with a RecursionError later.

The Exploit: Crashing the Interpreter

Exploiting this is trivially easy. We don't need shellcode or ROP chains; we just need JSON. The goal is to construct a nested structure that exceeds the Python interpreter's stack limit (usually 1000 frames) but would theoretically pass the Protobuf parser's default limit (usually 100) because of the bug.

The payload looks like this:

{
    "@type": "type.googleapis.com/google.protobuf.Any",
    "value": {
        "@type": "type.googleapis.com/google.protobuf.Any",
        "value": {
            "@type": "type.googleapis.com/google.protobuf.Any",
            "value": { ... repeat 1000 times ... }
        }
    }
}

When json_format.ParseDict() eats this, it dives deep.

  1. It sees the first Any.
  2. It looks inside, sees another Any (a WKT).
  3. It shortcuts the recursion check and calls the handler.
  4. The handler sees another Any.
  5. Goto step 3.

Eventually, CPython screams. A RecursionError is raised. If this exception isn't explicitly caught and handled (and most generic web frameworks won't catch a RecursionError gracefully during data binding), the worker process terminates. Do this continuously, and you have a persistent Denial of Service.

The Impact: Why Panic?

While this is "only" a Denial of Service, the context matters. Python Protobuf is widely used in API gateways, backend workers, and data processing pipelines.

Imagine a public-facing API endpoint that accepts JSON and converts it to Protobuf to talk to backend gRPC services. An attacker can hammer this endpoint with a few kilobytes of JSON data. Each request kills a worker process. If you are running a standard WSGI/ASGI server (like Gunicorn or Uvicorn) with a fixed number of workers, the attacker can starve the entire pool with very low bandwidth.

This isn't just about crashing a script; it's about resource exhaustion. The ease of exploitation (Network vector, Low complexity, No auth) gives it a CVSS score of 8.2 for a reason. It's a cheap, effective way to take down a Python-based microservice architecture.

Official Patches

GooglePull Request containing the fix

Fix Analysis (1)

Technical Appendix

CVSS Score
8.2/ 10
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:L

Affected Systems

Python applications using `google.protobuf` librarygRPC services accepting JSON transcodingData pipelines parsing untrusted Protobuf JSON

Affected Versions Detail

Product
Affected Versions
Fixed Version
protobuf-python
Google
>= 33.0See Vendor Advisory
AttributeDetail
CWECWE-674 (Uncontrolled Recursion)
CVSS v4.08.2 (High)
Attack VectorNetwork
ImpactAvailability (DoS)
Vulnerable Function_ConvertAnyMessage
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.003Application or System Exploitation
Impact
CWE-674
Uncontrolled Recursion

The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as memory or the program stack.

Known Exploits & Detection

Research PoCRecursive nested Any JSON payload

Vulnerability Timeline

Vulnerability identified
2026-01-22
Patch submitted (PR #25239)
2026-01-23
CVE-2026-0994 Published
2026-01-23

References & Sources

  • [1]NVD Record
  • [2]PT Security Advisory

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 3 hours ago•CVE-2026-54347
8.7

CVE-2026-54347: Stored Cross-Site Scripting in Froxlor DNS TXT Record Configuration

A critical stored Cross-Site Scripting (XSS) vulnerability was identified in Froxlor server administration software panel before version 2.3.8. Authenticated customers with DNS editor privileges can inject malicious JavaScript into DNS TXT records. Because the application processes these values via a raw formatting callback without context-aware HTML entity encoding, the payload executes in the security context of administrative users who view the affected domain's DNS zones.

Amit Schendel
Amit Schendel
3 views•6 min read
•about 4 hours ago•CVE-2026-54348
7.2

CVE-2026-54348: Second-Order SQL Injection in Froxlor API Layer

An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.

Amit Schendel
Amit Schendel
3 views•6 min read
•about 5 hours ago•CVE-2026-54543
5.4

CVE-2026-54543: DNS Resource Record (RR) Injection in Froxlor DomainZones API

CVE-2026-54543 is a DNS Resource Record (RR) Injection vulnerability in Froxlor, an open-source server administration control panel. Prior to version 2.3.8, the DomainZones.add API command failed to perform strict sanitization and validation on the user-controlled record (label) and type parameters before serializing them into BIND-compatible zone files. An authenticated customer with DNS zone management permissions can inject control characters, breaking out of the original record context to define unauthorized resource records within managed zones.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 5 hours ago•CVE-2026-42533
9.2

CVE-2026-42533: NGINX Map Directive and Regex Matching Pre-Auth Heap Buffer Overflow & Info Leak

CVE-2026-42533 is a critical security vulnerability discovered in NGINX Open Source, NGINX Plus, NGINX Ingress Controller, and related products, referred to as the 'Two-Pass Capture-Clobbering' bug. The flaw is situated within NGINX's internal evaluation engine when handling complex variables, exposing a heap-based buffer overflow and information leak when a configuration chains regular expression-based map directives with numbered capture groups. An unauthenticated remote attacker can exploit this weakness by transmitting crafted HTTP requests to trigger remote code execution or defeat ASLR.

Alon Barad
Alon Barad
7 views•7 min read
•about 6 hours ago•CVE-2026-55593
6.5

CVE-2026-55593: Persistent Administrative Hijacking via Cross-Site Request Forgery in Froxlor Ajax Router

Froxlor prior to version 2.3.8 contains a high-severity architectural flaw where the standalone lib/ajax.php entry point bypasses the centralized request validation in lib/init.php. Unauthenticated remote attackers can leverage Cross-Site Request Forgery (CSRF) to induce authenticated administrators to submit forged requests that modify API key whitelists and expiration dates, potentially yielding persistent, out-of-band administrative control.

Amit Schendel
Amit Schendel
4 views•8 min read
•about 7 hours ago•CVE-2026-62988
9.0

CVE-2026-62988: Multi-Factor Authentication and Credential Bypass in Froxlor API

An insecure data retrieval flaw in the Froxlor server administration panel API allows authenticated remote attackers to retrieve unredacted bcrypt password hashes and Base32-encoded Time-Based One-Time Password (TOTP) seeds. Affected endpoints include several 'get' and 'listing' handlers for customers, administrators, and FTP accounts. Utilizing these leaked parameters, attackers can crack the password hashes offline and concurrently generate valid second-factor authentication codes to completely bypass access controls.

Amit Schendel
Amit Schendel
8 views•6 min read