Skip to main content

Micronaut Core CVE-2026-44242

LOW
Uncontrolled Resource Consumption (CWE-400)
2026-05-06 https://github.com/micronaut-projects/micronaut-core GHSA-3rfq-4wpf-qqw3
3.7
CVSS 3.1 · GitHub Advisory

Severity by source

GitHub Advisory PRIMARY
3.7 LOW
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
Low

Lifecycle Timeline

3
Source Code Evidence Fetched
May 06, 2026 - 20:36 vuln.today
Analysis Generated
May 06, 2026 - 20:36 vuln.today
CVE Published
May 06, 2026 - 19:57 nvd
LOW 3.7

Blast Radius

ecosystem impact
† from your stack dependencies † transitive graph · vuln.today resolves 4-path depth
  • 215 maven packages depend on io.micronaut:micronaut-inject (28 direct, 187 indirect)

Ecosystem-wide dependent count for version 4.10.0.

DescriptionGitHub Advisory

Summary

ResourceBundleMessageSource maintains two caches: messageCache (bounded at 100 entries via ConcurrentLinkedHashMap) and bundleCache (unbounded ConcurrentHashMap). The bundleCache is keyed by (Locale, baseName) where the locale originates from the HTTP Accept-Language header. In applications that explicitly register a ResourceBundleMessageSource bean and serve HTML error responses, an unauthenticated attacker can exhaust heap memory by sending requests with large numbers of unique Accept-Language values, each causing a new entry in the unbounded bundleCache. Unlike GHSA-2hcp-gjrf-7fhc and the sibling messageCache (both bounded), bundleCache was not updated to use a bounded cache implementation.

Details

The bundleCache is initialized in inject/src/main/java/io/micronaut/context/i18n/ResourceBundleMessageSource.java at line 150:

java
// ResourceBundleMessageSource.java:139-152
protected Map<MessageKey, Optional<String>> buildMessageCache() {
    return new ConcurrentLinkedHashMap.Builder<MessageKey, Optional<String>>()
            .maximumWeightedCapacity(100)    // ← BOUNDED ✓
            .build();
}

protected Map<MessageKey, Optional<ResourceBundle>> buildBundleCache() {
    return new ConcurrentHashMap<>(18);      // ← UNBOUNDED ✗
}

The resolveBundle() method at line 169 inserts into bundleCache with no eviction policy:

java
// ResourceBundleMessageSource.java:169-185
private Optional<ResourceBundle> resolveBundle(Locale locale) {
    MessageKey key = new MessageKey(locale, baseName);
    final Optional<ResourceBundle> resourceBundle = bundleCache.get(key);
    if (resourceBundle != null) {
        return resourceBundle;
    } else {
        Optional<ResourceBundle> opt;
        try {
            opt = Optional.of(ResourceBundle.getBundle(baseName, locale, getClassLoader()));
        } catch (MissingResourceException e) {
            opt = Optional.empty();
        }
        bundleCache.put(key, opt);    // NO SIZE CHECK - unbounded growth
        return opt;
    }
}

The attack path requires:

  1. The application registers a ResourceBundleMessageSource bean (non-default, requires explicit user configuration).
  2. The attacker sends requests that trigger HTML error responses - i.e., requests with Accept: text/html to any URL that returns an error (e.g., 404 for any non-existent path).
  3. Each request uses a unique Accept-Language value (e.g., zz-AA, zz-AB, …).
  4. DefaultHtmlErrorResponseBodyProvider.error() calls messageSource.getMessage(code, locale)CompositeMessageSource delegates to ResourceBundleMessageSourceresolveBundle(locale) inserts one entry per unique locale into bundleCache.

For locales that don't match any bundle file, ResourceBundle.getBundle() throws MissingResourceException and Optional.empty() is stored - a low-cost sentinel. For locales that DO match a bundle, a full ResourceBundle object is retained in memory. In either case, the map itself and the MessageKey objects grow without bound.

Note: the messageCache is bounded at 100 entries but does not prevent bundleCache growth, as resolveBundle() is called directly (bypassing messageCache) whenever a messageCache miss occurs.

PoC

Against a Micronaut application with a ResourceBundleMessageSource bean registered (e.g., @Bean ResourceBundleMessageSource messages() { return new ResourceBundleMessageSource("messages"); }):

bash
# Flood bundleCache with unique locales via HTML error path
for i in $(seq 1 100000); do
  curl -s -o /dev/null \
    -H "Accept: text/html" \
    -H "Accept-Language: zz-$(printf '%04d' $i)" \
    "http://localhost:8080/nonexistent-path-$(printf '%06d' $i)" &
  [ $((i % 200)) -eq 0 ] && wait
done
wait

Each unique zz-XXXX tag creates one new bundleCache entry. The MessageKey (Locale + baseName) and map overhead cost approximately 100-200 bytes per entry. At 100,000 entries, heap consumption from the cache alone reaches roughly 20 MB - significant in resource-constrained deployments. If a locale matches a bundle file, retained ResourceBundle objects cost substantially more per entry.

Impact

  • Only affects applications that explicitly register a ResourceBundleMessageSource bean (not the default configuration).
  • Requires the ability to send HTTP requests with Accept: text/html headers and control over the Accept-Language value.
  • Memory grows approximately 100-200 bytes per novel locale (for non-matching locales) up to several KB per locale if bundles are found. Sustained attack over time causes gradual heap exhaustion.
  • Partial availability impact (A:L) under sustained attack in long-running services.

Recommended Fix

Apply the same bounded-cache pattern used for the sibling messageCache:

java
// In ResourceBundleMessageSource.java - replace buildBundleCache()
protected Map<MessageKey, Optional<ResourceBundle>> buildBundleCache() {
    return new ConcurrentLinkedHashMap.Builder<MessageKey, Optional<ResourceBundle>>()
            .maximumWeightedCapacity(50)    // small - one entry per (locale, baseName)
            .build();
}

The number of distinct resource bundle files is bounded at compile time; a limit of 50 entries is more than sufficient for any realistic i18n configuration while fully preventing unbounded growth.

AnalysisAI

Memory exhaustion in Micronaut Core's ResourceBundleMessageSource allows unauthenticated remote attackers to exhaust heap memory by sending HTTP requests with crafted Accept-Language headers that populate an unbounded bundleCache. Vulnerable applications must explicitly register a ResourceBundleMessageSource bean and serve HTML error responses; each unique locale value creates a persistent cache entry (100-200 bytes for non-matching locales, or several KB if bundles match), and sustained attack over thousands of requests causes gradual heap degradation with partial availability impact (CVSS 3.7, AC:H). The sibling messageCache is properly bounded at 100 entries, but bundleCache uses an uncontrolled ConcurrentHashMap, allowing unbounded growth keyed by (Locale, baseName) pairs derived from untrusted HTTP headers.

Technical ContextAI

ResourceBundleMessageSource is a Micronaut i18n component that caches localized resource bundles for message resolution. The vulnerability stems from the use of an unbounded ConcurrentHashMap for bundleCache in io.micronaut.context.i18n.ResourceBundleMessageSource (line 150), which stores Optional<ResourceBundle> objects keyed by MessageKey tuples containing Locale and baseName. The attack vector exploits the resolveBundle() method (line 169), which extracts Locale from the HTTP Accept-Language header and inserts it into bundleCache without size constraints. Unlike the sibling messageCache (which uses ConcurrentLinkedHashMap with maximumWeightedCapacity=100), bundleCache was initialized with only an initial capacity hint (18) and no eviction policy. CWE-400 (Uncontrolled Resource Consumption) applies because the cache growth is directly proportional to the number of unique Accept-Language values an attacker can inject. Applications using ResourceBundleMessageSource with explicit bean registration trigger DefaultHtmlErrorResponseBodyProvider.error(), which calls messageSource.getMessage(), ultimately invoking resolveBundle() for every unique locale in error responses.

RemediationAI

Upgrade Micronaut Core to version 4.10.22 or later. The vendor-released patch replaces the unbounded ConcurrentHashMap in buildBundleCache() with a bounded ConcurrentLinkedHashMap using maximumWeightedCapacity=50, mirroring the pattern already applied to the messageCache sibling (capacity 100). This fix fully prevents unbounded growth while accommodating realistic i18n configurations (compile-time bounded number of distinct resource bundle files). No workarounds are available for earlier versions other than disabling HTML error responses or removing the explicit ResourceBundleMessageSource bean registration, both of which have significant functional trade-offs. Deployment verification: after upgrading, confirm that io.micronaut:micronaut-inject is at 4.10.22+ by checking your build artifact manifest or dependency tree (mvn dependency:tree or gradle dependencies). See https://github.com/micronaut-projects/micronaut-core/releases/tag/v4.10.22 for detailed migration guidance.

More in Java

View all
CVE-2012-4681 CRITICAL POC
9.8 Aug 28

Oracle Java SE 7 Update 6 and earlier contains multiple sandbox bypass vulnerabilities via the ClassFinder and forName m

CVE-2015-7450 CRITICAL POC
9.8 Jan 02

Remote code execution in IBM Sterling B2B Integrator, Sterling Integrator, and Tivoli Common Reporting allows unauthenti

CVE-2013-2465 CRITICAL POC
9.8 Jun 18

Java Runtime Environment sandbox bypass via incorrect image channel verification in 2D component allows remote unauthent

CVE-2011-3544 CRITICAL POC
9.8 Oct 19

Oracle Java SE JDK/JRE 7 and 6 Update 27 and earlier allows remote code execution with complete system compromise throug

CVE-2010-1871 HIGH POC
8.8 Aug 05

JBoss Seam 2 in Red Hat JBoss EAP 4.3.0 fails to sanitize JBoss Expression Language inputs, allowing remote attackers to

CVE-2012-1723 CRITICAL POC
9.8 Jun 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 update 4 and earlier, 6 up

CVE-2013-0422 CRITICAL POC
9.8 Jan 10

Multiple vulnerabilities in Oracle Java 7 before Update 11 allow remote attackers to execute arbitrary code by (1) using

CVE-2012-0507 CRITICAL POC
9.8 Jun 07

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 2 and earlier, 6 Up

CVE-2015-4852 CRITICAL POC
9.8 Nov 18

The WLS Security component in Oracle WebLogic Server 10.3.6.0, 12.1.2.0, 12.1.3.0, and 12.2.1.0 allows remote attackers

CVE-2012-5076 CRITICAL POC
9.8 Oct 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 7 and earlier allow

CVE-2017-3066 CRITICAL POC
9.8 Apr 27

Remote unauthenticated attackers can execute arbitrary code on Adobe ColdFusion servers through Java deserialization fla

CVE-2012-0391 CRITICAL POC
9.8 Jan 08

The ExceptionDelegator component in Apache Struts before 2.2.3.1 interprets parameter values as OGNL expressions during

Share

CVE-2026-44242 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy