Conversation
There was a problem hiding this comment.
CVE-2026-44242 in io.micronaut:micronaut-inject - low severity
Micronaut Framework is a JVM-based full stack Java framework designed for building modular, easily testable JVM applications. Prior to 4.10.22, 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. This vulnerability is fixed in 4.10.22.
Details
Remediation Aikido suggests bumping this package to version 3.10.6 to resolve this issue
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
| context.setBody(value); // full body, overrides everything | ||
| return; | ||
| } else if (name.equals(QUERY_VALUE) || name.equals(PART) || name.equals(REQUEST_BEAN)) { | ||
| // The whole value is stored; StringExtractor recurses into bean fields. | ||
| context.setBodyElement(parameter.getName(), value); |
There was a problem hiding this comment.
🟡 Medium - Inherited Micronaut body fields are omitted from sink scanning
A Micronaut controller accepts a @Body or @RequestBean DTO whose user-controlled field is declared in a superclass, then forwards that field to a JDBC, command, or file sink. The new collector stores the DTO for scanning, but StringExtractor only reflects the concrete class's declared fields, so the inherited value is absent from StringsFromContext and the sink detector neither blocks nor reports the attack.
Show fix
Traverse the DTO superclass hierarchy when extracting structure fields, while preserving the existing transient/static/accessible-field safeguards, and add a Micronaut test with an inherited serialized field reaching a sink.
More info - Reply on this comment to give feedback or ignore the issue.
9ea80e9 to
e1184f8
Compare
| @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
| public static void after( | ||
| @Advice.Origin Executable method, | ||
| @Advice.Return(typing = DYNAMIC, readOnly = true) Object returned, |
There was a problem hiding this comment.
🟠 High - Void Micronaut filters are left uninstrumented, bypassing user blocking and rate limits
A Micronaut application uses the documented void @RequestFilter methods for SetUser and ShouldBlockRequest (Trigger). The wrapper matches those methods but binds @Advice.Return ... Object without optional=true, so Byte Buddy rejects the advice for void methods and leaves the original filter bytecode unchanged (Mechanism). The filters therefore run without a Zen context: SetUser cannot attach the user and ShouldBlockRequest returns no block, allowing blocked users and user/IP rate-limit decisions to continue (Consequence).
| @Advice.Return(typing = DYNAMIC, readOnly = true) Object returned, | |
| @Advice.Return(optional = true, typing = DYNAMIC, readOnly = true) Object returned, |
More info - Reply on this comment to give feedback or ignore the issue.
Instrument Micronaut controller methods and @RequestFilter methods: build the request context, read user input from @Body/@QueryValue/ @PathVariable/@Part/@RequestBean, and enforce IP, bot and allowlist blocking. The context is set on the controller thread, so protection also covers controllers offloaded with @ExecuteOn to a virtual thread; it is carried across that hop in an identity-keyed weak store keyed by the request, rather than on the request's own attribute map where the application could read or serialize it. Rate limiting and user blocking are handled by a user @ServerFilter (see docs/micronaut.md).
Add HyperSQL sample apps for Micronaut 5.1 (JDK 25) and 4.7 (JDK 17-24) with their e2e suites, and wire both into the end2end workflow - pinning the 5.x app to Java 25 and excluding the 4.x app from Java 25.
e1184f8 to
ada6970
Compare
| public ElementMatcher<? super MethodDescription> getMatcher() { | ||
| return isAnnotatedWith( | ||
| nameContainsIgnoreCase("io.micronaut.http.annotation") | ||
| .and(nameContainsIgnoreCase("Get") | ||
| .or(nameContainsIgnoreCase("Post")) | ||
| .or(nameContainsIgnoreCase("Put")) | ||
| .or(nameContainsIgnoreCase("Delete")) | ||
| .or(nameContainsIgnoreCase("Patch")) | ||
| .or(nameContainsIgnoreCase("RequestFilter")))); | ||
| } | ||
|
|
||
| @Override | ||
| public ElementMatcher<? super TypeDescription> getTypeMatcher() { | ||
| return hasSuperType(declaresMethod(getMatcher())); |
There was a problem hiding this comment.
🟡 Medium - Micronaut inbound blocking is absent without an application request filter
An application installs only the documented Java agent and has no @ServerFilter/@RequestFilter of its own; a request for an unmatched route, unsupported method, or a route rejected during argument binding therefore never invokes a controller. The agent instruments only already-existing route and request-filter methods and registers no Micronaut-wide request-entry hook, so WebRequestCollector.report is never called for those requests and configured IP or bot blocks are bypassed.
Show fix
Register an agent-owned Micronaut @ServerFilter(MATCH_ALL_PATTERN) (or instrument the framework's server request entry point) so every request establishes context and enforces inbound IP/UA/allowlist decisions before routing and binding, without requiring the application to add a filter.
More info - Reply on this comment to give feedback or ignore the issue.
Instrument Micronaut @controller methods to build the request context on the controller thread, so protection works on both event-loop and @ExecuteOn controllers without context propagation. Adds MicronautContextObject and MicronautAnnotationCollector (@Body/@QueryValue/@PathVariable/@Part/@RequestBean), inbound IP/UA/rate-limit blocking and response-status reporting.
Includes unit tests, a MicronautHyperSQL sample app and an end-to-end test wired into the e2e matrix (JDK 25). Reactive controllers are not yet supported.