Micronaut Core CVE-2026-44242
LOWSeverity by source
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
Lifecycle Timeline
3Blast Radius
ecosystem impact- 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:
// 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:
// 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:
- The application registers a
ResourceBundleMessageSourcebean (non-default, requires explicit user configuration). - The attacker sends requests that trigger HTML error responses - i.e., requests with
Accept: text/htmlto any URL that returns an error (e.g., 404 for any non-existent path). - Each request uses a unique
Accept-Languagevalue (e.g.,zz-AA,zz-AB, …). DefaultHtmlErrorResponseBodyProvider.error()callsmessageSource.getMessage(code, locale)→CompositeMessageSourcedelegates toResourceBundleMessageSource→resolveBundle(locale)inserts one entry per unique locale intobundleCache.
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"); }):
# 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
waitEach 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
ResourceBundleMessageSourcebean (not the default configuration). - Requires the ability to send HTTP requests with
Accept: text/htmlheaders and control over theAccept-Languagevalue. - 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:
// 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.
Oracle Java SE 7 Update 6 and earlier contains multiple sandbox bypass vulnerabilities via the ClassFinder and forName m
Remote code execution in IBM Sterling B2B Integrator, Sterling Integrator, and Tivoli Common Reporting allows unauthenti
Java Runtime Environment sandbox bypass via incorrect image channel verification in 2D component allows remote unauthent
Oracle Java SE JDK/JRE 7 and 6 Update 27 and earlier allows remote code execution with complete system compromise throug
JBoss Seam 2 in Red Hat JBoss EAP 4.3.0 fails to sanitize JBoss Expression Language inputs, allowing remote attackers to
Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 update 4 and earlier, 6 up
Multiple vulnerabilities in Oracle Java 7 before Update 11 allow remote attackers to execute arbitrary code by (1) using
Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 2 and earlier, 6 Up
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
Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 7 and earlier allow
Remote unauthenticated attackers can execute arbitrary code on Adobe ColdFusion servers through Java deserialization fla
The ExceptionDelegator component in Apache Struts before 2.2.3.1 interprets parameter values as OGNL expressions during
Same weakness CWE-400 – Uncontrolled Resource Consumption
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-3rfq-4wpf-qqw3