VYPR
High severityNVD Advisory· Published Mar 20, 2026· Updated Mar 25, 2026

Micronaut vulnerable to DoS via crafted form-urlencoded body binding with descending array indices

CVE-2026-33013

Description

Micronaut Framework is a JVM-based full stack Java framework designed for building modular, easily testable JVM applications. Versions prior to both 4.10.16 and 3.10.5 do not correctly handle descending array index order during form-urlencoded body binding in theJsonBeanPropertyBinder::expandArrayToThreshold, which allows remote attackers to cause a DoS (non-terminating loop, CPU exhaustion, and OutOfMemoryError) via crafted indexed form parameters (e.g., authors[1].name followed by authors[0].name). This issue has been fixed in versions 4.10.16 and 3.10.5.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Micronaut Framework DoS via crafted form-urlencoded body with descending array indices leads to infinite loop and CPU exhaustion.

Vulnerability

Overview CVE-2026-33013 is a denial-of-service (DoS) vulnerability in the Micronaut Framework's JsonBeanPropertyBinder::expandArrayToThreshold method. The bug occurs during form-urlencoded body binding when indexed form parameters are provided in descending order (e.g., authors[1].name followed by authors[0].name). This mishandling causes an infinite loop that exhausts CPU and memory, leading to an OutOfMemoryError [1][2].

Exploitation

An attacker can exploit this vulnerability by sending a crafted HTTP POST request with Content-Type: application/x-www-form-urlencoded containing such descending array indices. The request targets any endpoint that binds form data to a bean. No authentication or special privileges are required, making it easily exploitable from the network [2][4].

Impact

Successful exploitation results in a complete denial of service: the server enters a non-terminating loop, consuming 100% CPU and rapidly exhausting heap memory. This renders the application unavailable for legitimate users and may crash the JVM [1][3].

Mitigation

The issue has been patched in Micronaut versions 4.10.16 and 3.10.5. Users are strongly advised to upgrade immediately. The fix is documented in the GitHub security advisory GHSA-43w5-mmxv-cpvh [2], with corresponding commits and pull request references [3][4].

AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
io.micronaut:micronaut-json-coreMaven
>= 4.0.0-M1, < 4.10.164.10.16
io.micronaut:micronaut-json-coreMaven
>= 3.9.0, < 3.10.53.10.5
io.micronaut:micronaut-json-coreMaven
< 3.8.133.8.13

Affected products

2

Patches

1
1afe509677c5

fix: prevent denial of service submitting form-url-encoded payload (#12410)

3 files changed · +116 1
  • json-core/src/main/java/io/micronaut/json/bind/JsonBeanPropertyBinder.java+1 1 modified
    @@ -224,7 +224,7 @@ private ObjectBuilder getOrCreateNodeAtIndex(ArrayBuilder arrayNode, int arrayIn
     
         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);
                 }
             }
    
  • test-suite/build.gradle.kts+1 0 modified
    @@ -115,6 +115,7 @@ dependencies {
         testImplementation("io.micronaut.rxjava3:micronaut-rxjava3") {
             exclude(group = "io.micronaut")
         }
    +    testImplementation(libs.junit.jupiter.params)
     }
     
     tasks {
    
  • test-suite/src/test/java/io/micronaut/json/bind/JsonBeanPropertyBinderDenialOfServiceTest.java+114 0 added
    @@ -0,0 +1,114 @@
    +package io.micronaut.json.bind;
    +
    +import io.micronaut.context.annotation.Property;
    +import io.micronaut.context.annotation.Requires;
    +import io.micronaut.core.annotation.Introspected;
    +import io.micronaut.http.HttpRequest;
    +import io.micronaut.http.MediaType;
    +import io.micronaut.http.annotation.Body;
    +import io.micronaut.http.annotation.Controller;
    +import io.micronaut.http.annotation.Post;
    +import io.micronaut.http.client.BlockingHttpClient;
    +import io.micronaut.http.client.HttpClient;
    +import io.micronaut.http.client.annotation.Client;
    +import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
    +import jakarta.inject.Inject;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.ValueSource;
    +
    +import java.util.List;
    +import java.util.Objects;
    +
    +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +@Property(name = "spec.name", value = "JsonBeanPropertyBinderDenialOfServiceTest")
    +@MicronautTest
    +class JsonBeanPropertyBinderDenialOfServiceTest {
    +
    +    @Inject
    +    @Client("/") HttpClient httpClient;
    +
    +    @ParameterizedTest
    +    @ValueSource(strings = {
    +        "authors%5B0%5D.name=low&authors%5B1%5D.name=high",
    +        "authors%5B1%5D.name=high&authors%5B0%5D.name=low"
    +    })
    +    void submittingAFormUrlEncodedPayloadShouldNotCreateAnOutOfMemoryError(String body) {
    +        BlockingHttpClient client = httpClient.toBlocking();
    +        HttpRequest<?> request = HttpRequest.POST("/poc/book", body)
    +            .contentType(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
    +        Book b = assertDoesNotThrow(() -> client.retrieve(request, Book.class));
    +        Book expected = expected();
    +        assertEquals(expected, b);
    +    }
    +
    +    private static Book expected() {
    +        Book expected = new Book();
    +        Author firstAuthor = new Author();
    +        firstAuthor.setName("low");
    +        Author secondAuthor = new Author();
    +        secondAuthor.setName("high");
    +        expected.setAuthors(List.of(firstAuthor, secondAuthor));
    +        return expected;
    +    }
    +
    +    @Requires(property = "spec.name", value = "JsonBeanPropertyBinderDenialOfServiceTest")
    +    @Controller("/poc")
    +    static class PocController {
    +        @Post(uri = "/book", consumes = MediaType.APPLICATION_FORM_URLENCODED)
    +        Book bind(@Body Book book) { return book; }
    +    }
    +
    +    @Introspected
    +    static class Author {
    +        private String name;
    +        public String getName() { return name; }
    +        public void setName(String name) { this.name = name; }
    +
    +        @Override
    +        public final boolean equals(Object o) {
    +            if (!(o instanceof Author author)) return false;
    +
    +            return Objects.equals(name, author.name);
    +        }
    +
    +        @Override
    +        public int hashCode() {
    +            return Objects.hashCode(name);
    +        }
    +
    +        @Override
    +        public String toString() {
    +            return "Author{" +
    +                "name='" + name + '\'' +
    +                '}';
    +        }
    +    }
    +
    +    @Introspected
    +    static class Book {
    +        private List<Author> authors;
    +        public List<Author> getAuthors() { return authors; }
    +        public void setAuthors(List<Author> authors) { this.authors = authors; }
    +
    +        @Override
    +        public final boolean equals(Object o) {
    +            if (!(o instanceof Book book)) return false;
    +
    +            return Objects.equals(authors, book.authors);
    +        }
    +
    +        @Override
    +        public int hashCode() {
    +            return Objects.hashCode(authors);
    +        }
    +
    +        @Override
    +        public String toString() {
    +            return "Book{" +
    +                "authors=" + authors +
    +                '}';
    +        }
    +    }
    +}
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.