Introduction
An incomplete security fix in Apache MINA has reopened a critical remote code execution path through Java deserialization, scoring a 9.8 on the CVSS scale. The original vulnerability, CVE-2024-52046, was patched with a classname allowlist mechanism, but CVE-2026-41409 reveals that the allowlist was enforced too late in the deserialization pipeline, allowing malicious static initializers to execute before the check ever ran.
Apache MINA is a network application framework maintained by the Apache Software Foundation, designed for building high performance and highly scalable network applications in Java. It is widely used in enterprise environments and serves as the foundation for several Apache subprojects. Its presence in server side Java stacks makes deserialization vulnerabilities in MINA particularly consequential for organizations running networked services.
Technical Information
Root Cause: A Timing Problem in Allowlist Enforcement
CVE-2026-41409 is classified under CWE-502 (Deserialization of Untrusted Data). The vulnerability resides in AbstractIoBuffer.getObject(), which uses Java native deserialization to process incoming serialized data. When Apache addressed CVE-2024-52046, they introduced a classname allowlist to the custom ObjectInputStream used internally. The intent was to reject any class not explicitly approved before it could be instantiated.
The problem is that the allowlist was consulted too late. Two methods inside the custom ObjectInputStream contained distinct bypass paths.
Bypass Path 1: readClassDescriptor()
In the vulnerable code, after reading the class name via readUTF(), the code immediately called Class.forName(className, true, classLoader). The true parameter is critical here: it instructs the JVM to initialize the class, which means executing any static {} initializer block. The allowlist check happened only after this call returned. An attacker could craft a serialized payload referencing a class with a malicious static initializer. The JVM would load and initialize the class (executing the attacker's code), and only then would the allowlist reject it.
Bypass Path 2: resolveClass()
This method had a branching logic flaw. When desc.forClass() returned null, the code fell through to a Class.forName() call with no allowlist check at all. When forClass() returned a non null value, the allowlist was checked, but only after the class was already loaded. Both branches allowed an attacker to bypass the intended security control.
Attack Flow
- An attacker identifies a target application using Apache MINA that calls
IoBuffer.getObject(). This method is commonly invoked when aProtocolCodecFilteris configured withObjectSerializationCodecFactoryin the filter chain. - The attacker crafts a serialized Java object containing a reference to a class with a malicious
static {}initializer block. This initializer could execute arbitrary system commands, establish reverse shells, or perform other actions. - The attacker sends this crafted payload over the network to the MINA service.
- MINA's
AbstractIoBuffer.getObject()begins deserializing the payload. During deserialization, the customObjectInputStreamcalls eitherreadClassDescriptor()orresolveClass(). - In both methods,
Class.forName()is invoked before the allowlist is consulted. The JVM loads the attacker's class and executes its static initializer. - The malicious code runs with the privileges of the MINA application process. The allowlist check, which occurs afterward, throws an exception, but the damage is already done.
The attack requires no authentication and is exploitable over the network, which accounts for the 9.8 CVSS score.
Vulnerable Codepaths
An application is only affected if it calls IoBuffer.getObject(). This is most commonly triggered when using ObjectSerializationCodecFactory with a ProtocolCodecFilter in the MINA filter chain. Applications that do not use Java object serialization through MINA are not exposed.
Patch Information
The fix was committed by Emmanuel Lécharny on April 23, 2026 (commit 8b1dadb55b1d3f6b17f4ded10179e6b253ff1cc9) with the message: "Added patch regarding whitelist bypassing backported from mina-2.2.X." The commit modifies mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java and restructures both critical methods inside the custom ObjectInputStream.
Change 1: readClassDescriptor()
The fix inserts the allowlist check before the Class.forName() call. If the class name does not match any entry in the allowlist, a ClassNotFoundException is thrown immediately and the class is never loaded:
String className = readUTF(); // Only accept classes that are listed as acceptable // Apply class filter BEFORE calling Class.forName if (!acceptMatchers.stream().anyMatch(m -> m.matches(className))) { throw new ClassNotFoundException("Class not in accept list " + className); } // Use initialize=false to prevent static block execution during class loading Class clazz = Class.forName(className, true, classLoader);
Change 2: resolveClass()
This method was restructured more significantly. The patched code now applies the allowlist filter unconditionally at the very top of the method, before touching forClass() or Class.forName():
String className = desc.getName(); // apply acceptMatchers filter before any Class.forName() call, // regardless of whether forClass() is null or not if (!acceptMatchers.stream().anyMatch(m -> m.matches(className))) { throw new ClassNotFoundException("Class not in accept list " + className); } Class clazz = desc.forClass(); if (clazz != null) { return clazz; } try { return Class.forName(className, false, classLoader); } catch (ClassNotFoundException ex) { return super.resolveClass(desc); }
This eliminates both bypass paths: the forClass() == null path that previously skipped filtering entirely, and the forClass() != null path that checked only after loading.
The commit also includes 79 lines of new test cases in IoBufferTest.java that verify rejection behavior. For instance, testObjectSerializationReject() confirms that deserializing an object containing an unlisted class now throws ClassNotFoundException, and testNonserializableClassReject() / testNonserializableInterfaceReject() ensure non allowlisted classes and interfaces are properly blocked.
Configuration Hardening
Upgrading the library alone is necessary but not sufficient. By default, the decoder rejects all classes present in incoming data. Developers must explicitly configure which classes the decoder will accept using the ObjectSerializationDecoder instance. The following methods are provided:
/** * Accept class names where the supplied ClassNameMatcher matches for * deserialization, unless they are otherwise rejected. * * @param classNameMatcher the matcher to use */ public void accept(ClassNameMatcher classNameMatcher) /** * Accept class names that match the supplied pattern for * deserialization, unless they are otherwise rejected. * * @param pattern standard Java regexp */ public void accept(Pattern pattern) /** * Accept the wildcard specified classes for deserialization, * unless they are otherwise rejected. * * @param patterns Wildcard file name patterns as defined by * org.apache.commons.io.FilenameUtils(String, String) */ public void accept(String... patterns)
Organizations should configure these methods to restrict deserialization to the minimum set of trusted classes required by their application.
The fix ships in Apache MINA versions 2.0.28, 2.1.11, and 2.2.6.
Affected Systems and Versions
| MINA Branch | Affected Versions | Fixed Version |
|---|---|---|
| 2.0.x | 2.0.0 through 2.0.27 | 2.0.28 |
| 2.1.x | 2.1.0 through 2.1.10 | 2.1.11 |
| 2.2.x | 2.2.0 through 2.2.5 | 2.2.6 |
Only applications that call IoBuffer.getObject() are affected. This is most commonly triggered through the use of ObjectSerializationCodecFactory with a ProtocolCodecFilter in the MINA filter chain.
Apache has confirmed that subprojects including FtpServer, SSHd, and Vysper are not affected by this vulnerability.
Vendor Security History
CVE-2026-41409 is a direct bypass of the fix for CVE-2024-52046, which was itself a critical deserialization vulnerability in the same ObjectSerializationDecoder component. The original CVE-2024-52046 was widely tracked across multiple vendor security databases, including advisories from NetApp, F5, IBM, and SentinelOne. This level of attention indicates that threat actors actively monitor Apache MINA for deserialization flaws.
The Apache Software Foundation responded to both vulnerabilities with clear advisories and patches. The pattern of an incomplete initial fix followed by a bypass is not uncommon in deserialization vulnerability remediation, as the interaction between Java class loading, initialization, and security checks creates subtle timing windows that are easy to miss on the first pass.
References
- CVE-2026-41409: Apache MINA Deserialization Advisory (Apache Mailing List)
- CVE-2026-41409 Detail (NVD)
- CVE Record: CVE-2026-41409
- Patch Commit 8b1dadb (GitHub)
- CVE-2024-52046 Detail (NVD)
- GHSA-76h9-2vwh-w278: Apache MINA Deserialization RCE Vulnerability (GitHub Advisory)
- Apache MINA Project Home
- CVE-2024-52046: Apache Mina RCE Vulnerability (SentinelOne)
- CVE-2024-52046 Apache MINA Vulnerability Advisory (NetApp)
- CVE-2024-52046 (Vulnerability Lookup, CIRCL)



