Mar 17, 2026·6 min read·3 visits
A logic flaw in Micronaut's data binder allows unauthenticated attackers to cause an infinite loop by sending out-of-order array indices in form-urlencoded requests, leading to CPU exhaustion and application crashes.
The Micronaut Framework contains a Denial of Service (DoS) vulnerability within its form-urlencoded data binding mechanism. Specifically, the JsonBeanPropertyBinder class improperly handles descending array indices during parameter parsing, leading to an infinite loop and subsequent resource exhaustion. This flaw affects Micronaut 3.x versions prior to 3.10.5 and 4.x versions prior to 4.10.16.
The Micronaut Framework provides data binding capabilities to automatically map incoming HTTP request parameters to internal Java objects. This functionality simplifies controller logic by transforming raw application/x-www-form-urlencoded payloads into structured data types, including collections like lists and arrays.
The vulnerability resides in the io.micronaut:micronaut-json-core component, specifically within the JsonBeanPropertyBinder class. This class is responsible for expanding internal array structures to accommodate indexed parameters provided in the HTTP request body. When a client submits a payload containing array keys, the framework invokes the expandArrayToThreshold method to allocate sufficient space for the incoming data.
The core issue is a CWE-835 (Loop with Unreachable Exit Condition) vulnerability. The allocation logic relies on an unsafe comparison operator that fails to account for scenarios where the internal array is already larger than the required size. An attacker can exploit this oversight by supplying request parameters with descending indices, thereby triggering an infinite loop.
This flaw allows unauthenticated, remote attackers to degrade service availability. Successful exploitation directly causes CPU exhaustion and memory depletion, ultimately terminating the Java Virtual Machine (JVM) instance hosting the Micronaut application.
The root cause of this vulnerability is an improper loop termination condition in the expandArrayToThreshold method. The method accepts an arrayIndex integer and an ArrayBuilder object named arrayNode. Its purpose is to pad the arrayNode.values list with null elements until its size reaches arrayIndex + 1.
The original implementation utilized a while loop with a strict inequality check: while (arrayNode.values.size() != arrayIndex + 1). This logic implicitly assumes that arrayNode.values.size() will strictly start at a value less than arrayIndex + 1 and increment by exactly one during each iteration until equality is achieved.
This assumption holds true when clients provide array indices in ascending order (e.g., 0 then 1). However, the HTTP specification does not enforce parameter ordering. If a client provides indices in descending order, the arrayNode.values.size() can be greater than the required arrayIndex + 1 before the loop even begins.
When a lower index is processed after a higher index, the size() != arrayIndex + 1 condition evaluates to true. The loop executes, adding a new null element, which increments the size further away from the target value. The condition remains continuously true, resulting in an infinite loop that indefinitely allocates memory.
The vulnerable code path is straightforward and localized entirely within the JsonBeanPropertyBinder.java file. The original method implementation exposes the exact unsafe != comparator responsible for the condition evasion.
private void expandArrayToThreshold(int arrayIndex, ArrayBuilder arrayNode) {
if (arrayIndex < arraySizeThreshold) {
while (arrayNode.values.size() != arrayIndex + 1) {
arrayNode.values.add(FixedValue.NULL);
}
}
}The patch addresses the vulnerability by modifying the loop condition to use a less-than (<) operator. This ensures that the loop only executes if the current array size is genuinely smaller than the target size.
--- a/json-core/src/main/java/io/micronaut/json/bind/JsonBeanPropertyBinder.java
+++ b/json-core/src/main/java/io/micronaut/json/bind/JsonBeanPropertyBinder.java
@@ -224,7 +224,7 @@
private void expandArrayToThreshold(int arrayIndex, ArrayBuilder arrayNode) {
if (arrayIndex < arraySizeThreshold) {
- while (arrayNode.values.size() != arrayIndex + 1) {
+ while (arrayNode.values.size() < arrayIndex + 1) {
arrayNode.values.add(FixedValue.NULL);
}
}By replacing != with <, the method gracefully handles descending indices. If expandArrayToThreshold is called with an arrayIndex of 0 when the arrayNode size is already 2, the condition 2 < 0 + 1 evaluates to false immediately. The loop is bypassed, preventing the infinite execution cycle and memory exhaustion.
Exploitation requires the attacker to identify an endpoint that accepts HTTP POST requests with an application/x-www-form-urlencoded body. The target controller method must bind this request body to a Java object containing a collection, such as a List or array property.
The attacker crafts a payload specifying array parameters in descending order. The minimum requirement to trigger the bug is two parameters corresponding to the same array, where the first parameter has an index greater than the second parameter.
POST /poc/book HTTP/1.1
Content-Type: application/x-www-form-urlencoded
authors%5B1%5D.name=high&authors%5B0%5D.name=lowWhen the framework parses authors[1].name=high, it invokes expandArrayToThreshold(1, arrayNode). The arrayNode size increases from 0 to 2. When the framework subsequently parses authors[0].name=low, it invokes expandArrayToThreshold(0, arrayNode).
The loop evaluates 2 != 1 (true) and adds an element. The size becomes 3. The loop evaluates 3 != 1 (true) and adds another element. This sequence continues indefinitely. The request handling thread becomes permanently locked in this method execution.
The immediate consequence of this vulnerability is severe CPU exhaustion. The infinite loop operates without any blocking I/O calls or thread yielding, causing the affected thread to consume 100% of the CPU core it occupies. A relatively small number of malicious requests can quickly saturate all available request-processing threads, denying service to legitimate users.
Simultaneously, the infinite loop continuously appends FixedValue.NULL objects to the arrayNode.values list. This results in rapid and unbounded heap memory allocation. The garbage collector cannot reclaim this memory because the list remains actively referenced within the execution scope of the vulnerable method.
The application will inevitably throw a java.lang.OutOfMemoryError (OOM). Depending on the JVM configuration and the hosting environment, an OOM exception typically leads to process termination. In containerized environments like Kubernetes, the pod will fail its liveness probes and be restarted, causing brief but repeated service outages if the attack is sustained.
The definitive remediation for this vulnerability is upgrading the Micronaut Framework to a patched version. Development teams must update their dependency manifests to require Micronaut 3.10.5 (for the 3.x release line) or Micronaut 4.10.16 (for the 4.x release line).
For environments where immediate patching is not feasible, network-level mitigation is challenging. Traditional Web Application Firewalls (WAFs) often lack the capability to validate the sequential ordering of array indices within form-urlencoded request bodies. Attempting to write regular expressions to block descending indices is highly prone to bypasses and false positives.
Organizations unable to patch immediately should implement strict rate limiting on endpoints known to bind complex objects from form-urlencoded data. Additionally, monitoring infrastructure should be configured to alert on sudden spikes in CPU utilization correlated with rapid heap growth.
Configuring the JVM with -XX:+HeapDumpOnOutOfMemoryError and -XX:+ExitOnOutOfMemoryError ensures that the application cleanly restarts upon memory exhaustion rather than lingering in a degraded, unstable state.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Micronaut Framework Micronaut | 3.0.0 <= 3.10.4 | 3.10.5 |
Micronaut Framework Micronaut | 4.0.0 <= 4.10.15 | 4.10.16 |
| Attribute | Detail |
|---|---|
| Vulnerability Type | Denial of Service (DoS) |
| CWE ID | CWE-835 |
| Attack Vector | Network (HTTP POST) |
| Impact | CPU Exhaustion and OutOfMemoryError (Crash) |
| Authentication Required | None |
| Patched Versions | 3.10.5, 4.10.16 |
The program contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.