VYPR
Critical severityCISA KEVNVD Advisory· Published May 24, 2023· Updated Oct 21, 2025

Apache RocketMQ: Possible remote code execution vulnerability when using the update configuration function

CVE-2023-33246

Description

For RocketMQ versions 5.1.0 and below, under certain conditions, there is a risk of remote command execution.

Several components of RocketMQ, including NameServer, Broker, and Controller, are leaked on the extranet and lack permission verification, an attacker can exploit this vulnerability by using the update configuration function to execute commands as the system users that RocketMQ is running as. Additionally, an attacker can achieve the same effect by forging the RocketMQ protocol content.

To prevent these attacks, users are recommended to upgrade to version 5.1.1 or above for using RocketMQ 5.x or 4.9.6 or above for using RocketMQ 4.x .

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.rocketmq:rocketmq-brokerMaven
>= 5.0.0, < 5.1.15.1.1
org.apache.rocketmq:rocketmq-namesrvMaven
>= 4.0.0, < 4.9.64.9.6
org.apache.rocketmq:rocketmq-controllerMaven
>= 5.0.0, < 5.1.15.1.1
org.apache.rocketmq:rocketmq-namesrvMaven
>= 5.0.0, < 5.1.15.1.1

Affected products

1
  • Apache Software Foundation/Apache RocketMQv5
    Range: 0

Patches

2
c3ada731405c

Make configPath unable to update at runtime

https://github.com/apache/rocketmqrongtongMay 11, 2023via ghsa
2 files changed · +46 0
  • namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java+6 0 modified
    @@ -581,6 +581,12 @@ private RemotingCommand updateConfig(ChannelHandlerContext ctx, RemotingCommand
                     return response;
                 }
     
    +            if (properties.containsKey("kvConfigPath") || properties.containsKey("configStorePathName")) {
    +                response.setCode(ResponseCode.NO_PERMISSION);
    +                response.setRemark("Can not update config path");
    +                return response;
    +            }
    +
                 this.namesrvController.getConfiguration().update(properties);
             }
     
    
  • namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java+40 0 modified
    @@ -20,10 +20,13 @@
     import io.netty.channel.ChannelHandlerContext;
     import java.lang.reflect.Field;
     import java.lang.reflect.Modifier;
    +import java.nio.charset.StandardCharsets;
     import java.util.ArrayList;
     import java.util.HashMap;
     import java.util.Map;
    +import java.util.Properties;
     import java.util.concurrent.ConcurrentHashMap;
    +import org.apache.rocketmq.common.MixAll;
     import org.apache.rocketmq.common.TopicConfig;
     import org.apache.rocketmq.logging.InternalLogger;
     import org.apache.rocketmq.common.namesrv.NamesrvConfig;
    @@ -159,6 +162,43 @@ public void testProcessRequest_DeleteKVConfig() throws RemotingCommandException
                 .isNull();
         }
     
    +    @Test
    +    public void testProcessRequest_UpdateConfigPath() throws RemotingCommandException {
    +        final RemotingCommand updateConfigRequest = RemotingCommand.createRequestCommand(RequestCode.UPDATE_NAMESRV_CONFIG, null);
    +        Properties properties = new Properties();
    +
    +        // Update allowed value
    +        properties.setProperty("enableTopicList", "true");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        RemotingCommand response = defaultRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
    +
    +        //update disallowed value
    +        properties.clear();
    +        properties.setProperty("configStorePathName", "test/path");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        response = defaultRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.NO_PERMISSION);
    +        assertThat(response.getRemark()).contains("Can not update config path");
    +
    +        //update disallowed values
    +        properties.clear();
    +        properties.setProperty("kvConfigPath", "test/path");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        response = defaultRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.NO_PERMISSION);
    +        assertThat(response.getRemark()).contains("Can not update config path");
    +    }
    +
         @Test
         public void testProcessRequest_RegisterBroker() throws RemotingCommandException,
             NoSuchFieldException, IllegalAccessException {
    
9d411cf04a69

Make configPath unable to update at runtime (#6733)

https://github.com/apache/rocketmqrongtongMay 11, 2023via ghsa
6 files changed · +163 2
  • broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java+9 1 modified
    @@ -775,13 +775,21 @@ private synchronized RemotingCommand updateBrokerConfig(ChannelHandlerContext ct
                     String bodyStr = new String(body, MixAll.DEFAULT_CHARSET);
                     Properties properties = MixAll.string2Properties(bodyStr);
                     if (properties != null) {
    -                    LOGGER.info("updateBrokerConfig, new config: [{}] client: {} ", properties, ctx.channel().remoteAddress());
    +                    LOGGER.info("updateBrokerConfig, new config: [{}] client: {} ", properties, callerAddress);
    +
    +                    if (properties.containsKey("brokerConfigPath")) {
    +                        response.setCode(ResponseCode.NO_PERMISSION);
    +                        response.setRemark("Can not update config path");
    +                        return response;
    +                    }
    +
                         this.brokerController.getConfiguration().update(properties);
                         if (properties.containsKey("brokerPermission")) {
                             long stateMachineVersion = brokerController.getMessageStore() != null ? brokerController.getMessageStore().getStateMachineVersion() : 0;
                             this.brokerController.getTopicConfigManager().getDataVersion().nextVersion(stateMachineVersion);
                             this.brokerController.registerBrokerAll(false, false, true);
                         }
    +
                     } else {
                         LOGGER.error("string2Properties error");
                         response.setCode(ResponseCode.SYSTEM_ERROR);
    
  • broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java+32 0 modified
    @@ -24,8 +24,10 @@
     import java.net.SocketAddress;
     import java.net.UnknownHostException;
     import java.nio.ByteBuffer;
    +import java.nio.charset.StandardCharsets;
     import java.util.HashMap;
     import java.util.Map;
    +import java.util.Properties;
     import java.util.Set;
     import java.util.concurrent.ConcurrentMap;
     import java.util.concurrent.atomic.LongAdder;
    @@ -276,6 +278,36 @@ public void testGetBrokerConfig() throws Exception {
             assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
         }
     
    +    @Test
    +    public void testProcessRequest_UpdateConfigPath() throws RemotingCommandException {
    +        final RemotingCommand updateConfigRequest = RemotingCommand.createRequestCommand(RequestCode.UPDATE_BROKER_CONFIG, null);
    +        Properties properties = new Properties();
    +
    +        ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
    +        when(ctx.channel()).thenReturn(null);
    +
    +        // Update allowed value
    +        properties.setProperty("allAckInSyncStateSet", "true");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        RemotingCommand response = adminBrokerProcessor.processRequest(ctx, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
    +
    +        //update disallowed value
    +        properties.clear();
    +        properties.setProperty("brokerConfigPath", "test/path");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        response = adminBrokerProcessor.processRequest(ctx, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.NO_PERMISSION);
    +        assertThat(response.getRemark()).contains("Can not update config path");
    +
    +    }
    +
         @Test
         public void testSearchOffsetByTimestamp() throws Exception {
             messageStore = mock(MessageStore.class);
    
  • controller/src/main/java/org/apache/rocketmq/controller/processor/ControllerRequestProcessor.java+6 0 modified
    @@ -241,6 +241,12 @@ private RemotingCommand handleUpdateControllerConfig(ChannelHandlerContext ctx,
                     return response;
                 }
     
    +            if (properties.containsKey("configStorePath")) {
    +                response.setCode(ResponseCode.NO_PERMISSION);
    +                response.setRemark("Can not update config path");
    +                return response;
    +            }
    +
                 this.controllerManager.getConfiguration().update(properties);
             }
     
    
  • controller/src/test/java/org/apache/rocketmq/controller/ControllerRequestProcessorTest.java+70 0 added
    @@ -0,0 +1,70 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +
    +package org.apache.rocketmq.controller;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.Properties;
    +import org.apache.rocketmq.common.ControllerConfig;
    +import org.apache.rocketmq.common.MixAll;
    +import org.apache.rocketmq.controller.processor.ControllerRequestProcessor;
    +import org.apache.rocketmq.remoting.netty.NettyClientConfig;
    +import org.apache.rocketmq.remoting.netty.NettyServerConfig;
    +import org.apache.rocketmq.remoting.protocol.RemotingCommand;
    +import org.apache.rocketmq.remoting.protocol.RequestCode;
    +import org.apache.rocketmq.remoting.protocol.ResponseCode;
    +import org.junit.Before;
    +import org.junit.Test;
    +
    +import static org.assertj.core.api.Assertions.assertThat;
    +
    +public class ControllerRequestProcessorTest {
    +
    +    private ControllerRequestProcessor controllerRequestProcessor;
    +
    +    @Before
    +    public void init() throws Exception {
    +        controllerRequestProcessor = new ControllerRequestProcessor(new ControllerManager(new ControllerConfig(), new NettyServerConfig(), new NettyClientConfig()));
    +    }
    +
    +    @Test
    +    public void testProcessRequest_UpdateConfigPath() throws Exception {
    +        final RemotingCommand updateConfigRequest = RemotingCommand.createRequestCommand(RequestCode.UPDATE_CONTROLLER_CONFIG, null);
    +        Properties properties = new Properties();
    +
    +        // Update allowed value
    +        properties.setProperty("notifyBrokerRoleChanged", "true");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        RemotingCommand response = controllerRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
    +
    +        // Update disallowed value
    +        properties.clear();
    +        properties.setProperty("configStorePath", "test/path");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        response = controllerRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.NO_PERMISSION);
    +        assertThat(response.getRemark()).contains("Can not update config path");
    +
    +    }
    +}
    
  • namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java+6 0 modified
    @@ -627,6 +627,12 @@ private RemotingCommand updateConfig(ChannelHandlerContext ctx, RemotingCommand
                     return response;
                 }
     
    +            if (properties.containsKey("kvConfigPath") || properties.containsKey("configStorePathName")) {
    +                response.setCode(ResponseCode.NO_PERMISSION);
    +                response.setRemark("Can not update config path");
    +                return response;
    +            }
    +
                 this.namesrvController.getConfiguration().update(properties);
             }
     
    
  • namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/RequestProcessorTest.java+40 1 modified
    @@ -21,10 +21,13 @@
     import java.lang.reflect.Field;
     import java.lang.reflect.Modifier;
     import java.net.InetSocketAddress;
    +import java.nio.charset.StandardCharsets;
     import java.util.ArrayList;
     import java.util.HashMap;
     import java.util.Map;
    +import java.util.Properties;
     import java.util.concurrent.ConcurrentHashMap;
    +import org.apache.rocketmq.common.MixAll;
     import org.apache.rocketmq.common.TopicConfig;
     import org.apache.rocketmq.common.UtilAll;
     import org.apache.rocketmq.common.namesrv.NamesrvConfig;
    @@ -85,7 +88,6 @@ public void init() throws Exception {
     
             clientRequestProcessor = new ClientRequestProcessor(namesrvController);
     
    -
             registerRouteInfoManager();
     
             logger = mock(Logger.class);
    @@ -178,6 +180,43 @@ public void testProcessRequest_UnSupportedRequest() throws RemotingCommandExcept
             assertThat(response.getCode()).isEqualTo(ResponseCode.REQUEST_CODE_NOT_SUPPORTED);
         }
     
    +    @Test
    +    public void testProcessRequest_UpdateConfigPath() throws RemotingCommandException {
    +        final RemotingCommand updateConfigRequest = RemotingCommand.createRequestCommand(RequestCode.UPDATE_NAMESRV_CONFIG, null);
    +        Properties properties = new Properties();
    +
    +        // Update allowed value
    +        properties.setProperty("enableTopicList", "true");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        RemotingCommand response = defaultRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
    +
    +        //update disallowed value
    +        properties.clear();
    +        properties.setProperty("configStorePathName", "test/path");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        response = defaultRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.NO_PERMISSION);
    +        assertThat(response.getRemark()).contains("Can not update config path");
    +
    +        //update disallowed values
    +        properties.clear();
    +        properties.setProperty("kvConfigPath", "test/path");
    +        updateConfigRequest.setBody(MixAll.properties2String(properties).getBytes(StandardCharsets.UTF_8));
    +
    +        response = defaultRequestProcessor.processRequest(null, updateConfigRequest);
    +
    +        assertThat(response).isNotNull();
    +        assertThat(response.getCode()).isEqualTo(ResponseCode.NO_PERMISSION);
    +        assertThat(response.getRemark()).contains("Can not update config path");
    +    }
    +
         @Test
         public void testProcessRequest_RegisterBroker() throws RemotingCommandException,
             NoSuchFieldException, IllegalAccessException {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.