VYPR
Low severityNVD Advisory· Published Apr 1, 2025· Updated Apr 2, 2025

Apache ActiveMQ Artemis: Address routing-type can be updated by user without the createAddress permission

CVE-2025-27427

Description

A vulnerability exists in Apache ActiveMQ Artemis whereby a user with the createDurableQueue or createNonDurableQueue permission on an address can augment the routing-type supported by that address even if said user doesn't have the createAddress permission for that particular address. When combined with the send permission and automatic queue creation a user could successfully send a message with a routing-type not supported by the address when that message should actually be rejected on the basis that the user doesn't have permission to change the routing-type of the address.

This issue affects Apache ActiveMQ Artemis from 2.0.0 through 2.39.0.

Users are recommended to upgrade to version 2.40.0 which fixes the issue.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

In Apache ActiveMQ Artemis 2.0.0–2.39.0, users with createDurableQueue/createNonDurableQueue permission can alter an address's routing-type, bypassing createAddress restrictions and allowing invalid messages.

Vulnerability

Overview

CVE-2025-27427 is a privilege escalation vulnerability in Apache ActiveMQ Artemis that arises from insufficient permission checks during queue creation. According to the official description, a user who holds the createDurableQueue or createNonDurableQueue permission on an address can modify the set of routing-types supported by that address, even if the user lacks the createAddress permission for that same address [1]. This means the user can effectively change the address's routing-type without proper authorization.

Exploitation

Scenario

The exploitation requires that the attacker also has the send permission on the address and that automatic queue creation is enabled. Under these conditions, the attacker can create a queue with a routing-type (e.g., MULTICAST) that differs from the address's original routing-type (e.g., ANYCAST). Because the routing-type augmentation happens implicitly during queue creation, the system does not reject the operation. The attacker can then send a message with a routing-type that the address was not originally configured to support, bypassing the intended routing-type enforcement [1][2].

Impact

An authenticated user who does not have full administrative privileges can effectively escalate their permissions to alter address behavior. This could lead to message misrouting or delivery to unintended consumers, disrupting message flow and potentially causing information disclosure or denial of service. The vulnerability affects all versions of Apache ActiveMQ Artemis from 2.0.0 through 2.39.0 [1][4].

Mitigation

The issue is fixed in version 2.40.0, which includes a patch (ARTEMIS-5346) that enforces a proper check against the createAddress permission when a queue request would change the routing-type of an address [2][3]. Users are strongly recommended to upgrade to 2.40.0 or later. No workarounds have been published.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.activemq:artemis-serverMaven
>= 2.0.0, < 2.40.02.40.0

Affected products

13

Patches

2
6ab458015689

ARTEMIS-5346 fix bug exposed by new logic

https://github.com/apache/activemq-artemisJustin BertramMar 13, 2025via ghsa
1 file changed · +5 3
  • artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQConsumer.java+5 3 modified
    @@ -35,6 +35,7 @@
     import org.apache.activemq.artemis.api.core.ICoreMessage;
     import org.apache.activemq.artemis.api.core.Message;
     import org.apache.activemq.artemis.api.core.QueueConfiguration;
    +import org.apache.activemq.artemis.api.core.RoutingType;
     import org.apache.activemq.artemis.api.core.SimpleString;
     import org.apache.activemq.artemis.core.client.impl.ClientConsumerImpl;
     import org.apache.activemq.artemis.core.protocol.openwire.OpenWireConstants;
    @@ -215,6 +216,7 @@ private SimpleString createTopicSubscription(boolean isDurable,
              if (info.getDestination().isComposite()) {
                 queueName =  queueName.concat(physicalName);
              }
    +         QueueConfiguration queueConfiguration = QueueConfiguration.of(queueName).setAddress(address).setRoutingType(RoutingType.MULTICAST).setFilterString(selector).setInternal(internalAddress);
              QueueQueryResult result = session.getCoreSession().executeQueueQuery(queueName);
              if (result.isExists()) {
                 // Already exists
    @@ -235,10 +237,10 @@ private SimpleString createTopicSubscription(boolean isDurable,
                    session.getCoreSession().deleteQueue(queueName);
     
                    // Create the new one
    -               session.getCoreSession().createQueue(QueueConfiguration.of(queueName).setAddress(address).setFilterString(selector).setInternal(internalAddress));
    +               session.getCoreSession().createQueue(queueConfiguration);
                 }
              } else {
    -            session.getCoreSession().createQueue(QueueConfiguration.of(queueName).setAddress(address).setFilterString(selector).setInternal(internalAddress));
    +            session.getCoreSession().createQueue(queueConfiguration);
              }
           } else {
              // The consumer may be using FQQN in which case the queue might already exist.
    @@ -251,7 +253,7 @@ private SimpleString createTopicSubscription(boolean isDurable,
                 queueName = SimpleString.of(UUID.randomUUID().toString());
              }
     
    -         session.getCoreSession().createQueue(QueueConfiguration.of(queueName).setAddress(address).setFilterString(selector).setDurable(false).setTemporary(true).setInternal(internalAddress));
    +         session.getCoreSession().createQueue(QueueConfiguration.of(queueName).setAddress(address).setRoutingType(RoutingType.MULTICAST).setFilterString(selector).setDurable(false).setTemporary(true).setInternal(internalAddress));
           }
     
           return queueName;
    
2216a75a57f0

ARTEMIS-5346 check routing-type when creating queue

https://github.com/apache/activemq-artemisJustin BertramJan 7, 2025via ghsa
2 files changed · +118 1
  • artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java+1 1 modified
    @@ -753,7 +753,7 @@ public Queue createQueue(QueueConfiguration queueConfiguration) throws Exception
     
           AddressSettings as = server.getAddressSettingsRepository().getMatch(queueConfiguration.getAddress().toString());
     
    -      if (as.isAutoCreateAddresses() && server.getAddressInfo(queueConfiguration.getAddress()) == null) {
    +      if (as.isAutoCreateAddresses() && (server.getAddressInfo(queueConfiguration.getAddress()) == null || !server.getAddressInfo(queueConfiguration.getAddress()).getRoutingTypes().contains(queueConfiguration.getRoutingType()))) {
              securityCheck(queueConfiguration.getAddress(), queueConfiguration.getName(), CheckType.CREATE_ADDRESS, this);
           }
     
    
  • tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java+117 0 modified
    @@ -646,6 +646,123 @@ public void testJAASSecurityManagerAuthorizationNegative() throws Exception {
           }
        }
     
    +   @Test
    +   public void testJAASSecurityManagerCreateQueueWithDifferentRoutingTypeAsAddressNegative() throws Exception {
    +      final SimpleString ADDRESS = SimpleString.of("address");
    +      final SimpleString DURABLE_QUEUE = SimpleString.of("durableQueue");
    +      final SimpleString NON_DURABLE_QUEUE = SimpleString.of("nonDurableQueue");
    +      final SimpleString JMS = SimpleString.of("jms");
    +
    +      ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin");
    +      ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
    +      Set<Role> roles = new HashSet<>();
    +      roles.add(new Role("programmers", false, false, true, false, true, false, false, false, false, false, false, false));
    +      server.getConfiguration().putSecurityRoles("#", roles);
    +      server.start();
    +      server.addAddressInfo(new AddressInfo(ADDRESS, RoutingType.ANYCAST));
    +      server.addAddressInfo(new AddressInfo(JMS, RoutingType.ANYCAST));
    +
    +      ClientSessionFactory cf = createSessionFactory(locator);
    +      ClientSession session = addClientSession(cf.createSession("first", "secret", false, true, true, false, 0));
    +
    +      ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://0");
    +
    +      // Explicit attempt to modify address routing type with a durable queue
    +      try {
    +         session.createQueue(QueueConfiguration.of(DURABLE_QUEUE).setAddress(ADDRESS).setRoutingType(RoutingType.MULTICAST));
    +         fail("should throw exception here");
    +      } catch (ActiveMQException e) {
    +         assertTrue(e.getMessage().contains("User: first"));
    +         assertTrue(e.getMessage().contains("does not have permission='CREATE_ADDRESS' for queue durableQueue on address address"));
    +      }
    +
    +      // Implicit attempt to modify address routing type with a durable queue using auto-create via JMS
    +      try (Connection c = connectionFactory.createConnection("first", "secret")) {
    +         c.setClientID("myClientID");
    +         Session s = c.createSession();
    +         s.createDurableSubscriber(s.createTopic(JMS.toString()), "foo");
    +         fail("should throw exception here");
    +      } catch (JMSException e) {
    +         assertTrue(e.getMessage().contains("User: first"));
    +         assertTrue(e.getMessage().contains("does not have permission='CREATE_ADDRESS' for queue myClientID.foo on address jms"));
    +      }
    +
    +      // Explicit attempt to modify address routing type with a non-durable queue
    +      try {
    +         session.createQueue(QueueConfiguration.of(NON_DURABLE_QUEUE).setAddress(ADDRESS).setDurable(false).setRoutingType(RoutingType.MULTICAST));
    +         fail("should throw exception here");
    +      } catch (ActiveMQException e) {
    +         assertTrue(e.getMessage().contains("User: first"));
    +         assertTrue(e.getMessage().contains("does not have permission='CREATE_ADDRESS' for queue nonDurableQueue on address address"));
    +      }
    +
    +      // Implicit attempt to modify address routing type with a non-durable queue using auto-create via JMS
    +      try (Connection c = connectionFactory.createConnection("first", "secret")) {
    +         Session s = c.createSession();
    +         s.createConsumer(s.createTopic(JMS.toString()));
    +         fail("should throw exception here");
    +      } catch (JMSException e) {
    +         assertTrue(e.getMessage().contains("User: first"));
    +         assertTrue(e.getMessage().contains("does not have permission='CREATE_ADDRESS'"));
    +      }
    +   }
    +
    +   @Test
    +   public void testJAASSecurityManagerCreateQueueWithDifferentRoutingTypeAsAddress() throws Exception {
    +      final SimpleString ADDRESS = SimpleString.of("address");
    +      final SimpleString DURABLE_QUEUE = SimpleString.of("durableQueue");
    +      final SimpleString NON_DURABLE_QUEUE = SimpleString.of("nonDurableQueue");
    +      final SimpleString JMS = SimpleString.of("jms");
    +
    +      ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin");
    +      ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
    +      Set<Role> roles = new HashSet<>();
    +      roles.add(new Role("programmers", false, true, true, false, true, false, false, false, true, false, false, false));
    +      server.getConfiguration().putSecurityRoles("#", roles);
    +      server.start();
    +      server.addAddressInfo(new AddressInfo(ADDRESS, RoutingType.ANYCAST));
    +
    +      ClientSessionFactory cf = createSessionFactory(locator);
    +      ClientSession session = addClientSession(cf.createSession("first", "secret", false, true, true, false, 0));
    +
    +      ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://0");
    +
    +      // Explicit attempt to modify address routing type with a durable queue
    +      try {
    +         session.createQueue(QueueConfiguration.of(DURABLE_QUEUE).setAddress(ADDRESS).setRoutingType(RoutingType.MULTICAST));
    +      } catch (ActiveMQException e) {
    +         e.printStackTrace();
    +         fail("should not throw exception here");
    +      }
    +
    +      // Implicit attempt to modify address routing type with a durable queue using auto-create via JMS
    +      try (Connection c = connectionFactory.createConnection("first", "secret")) {
    +         c.setClientID("myClientID");
    +         Session s = c.createSession();
    +         s.createDurableSubscriber(s.createTopic(JMS.toString()), "foo");
    +      } catch (JMSException e) {
    +         e.printStackTrace();
    +         fail("should not throw exception here");
    +      }
    +
    +      // Explicit attempt to modify address routing type with a non-durable queue
    +      try {
    +         session.createQueue(QueueConfiguration.of(NON_DURABLE_QUEUE).setAddress(ADDRESS).setDurable(false).setRoutingType(RoutingType.MULTICAST));
    +      } catch (ActiveMQException e) {
    +         e.printStackTrace();
    +         fail("should not throw exception here");
    +      }
    +
    +      // Implicit attempt to modify address routing type with a non-durable queue using auto-create via JMS
    +      try (Connection c = connectionFactory.createConnection("first", "secret")) {
    +         Session s = c.createSession();
    +         s.createConsumer(s.createTopic(JMS.toString()));
    +      } catch (JMSException e) {
    +         e.printStackTrace();
    +         fail("should not throw exception here");
    +      }
    +   }
    +
        @Test
        // this is for backwards compatibility with the pre-FQQN syntax from ARTEMIS-592
        public void testJAASSecurityManagerAuthorizationSameAddressDifferentQueuesDotSyntax() throws Exception {
    

Vulnerability mechanics

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

References

7

News mentions

0

No linked articles in our index yet.