CVE-2026-108946

Authorization Bypass
Affects
ActiveMQ
in
Apache ActiveMQ
No items found.
Versions
<5.19.12, >=6.0.0 <6.3.3

Patch Available.

Exclamation circle icon
Patch Available

This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.

Overview

Apache ActiveMQ Classic is an open-source Java message broker that provides asynchronous messaging for applications. It supports JMS 1.1 and multiple wire protocols, including OpenWire, AMQP, MQTT and STOMP. Broker and client components are published as Maven artifacts under org.apache.activemq. ActiveMQ Classic is distinct from Apache ActiveMQ Artemis, which has its own broker implementation and release lines.

An authorization bypass vulnerability (CVE-2026-108946) has been identified in the Apache ActiveMQ Classic broker, which allows an authenticated client to act on another connection's consumers and temporary destinations by putting that connection's id in its own commands. The attacker can consume from the victim's temporary queues and topics, tear down the victim's live subscriptions, and permanently delete the victim's in-flight, unacknowledged messages.

Per OWASP: Access control enforces policy such that users cannot act outside of their intended permissions. Failures typically lead to unauthorized information disclosure, modification, or destruction of all data or performing a business function outside the user's limits.

This issue affects multiple versions of Apache ActiveMQ Classic.

‍

Details

Module Info

Vulnerability Info

This High-severity vulnerability is found in the org.apache.activemq:activemq-broker package in multiple versions of Apache ActiveMQ Classic.

Every OpenWire command a client sends carries ids chosen by the client: a ConsumerId, ProducerId or SessionId embeds the ConnectionId it belongs to. The broker's TransportConnection resolves the connection state for each command through its TransportConnectionStateRegister. For an ordinary client connection this is a SingleTransportConnectionStateRegister, which holds exactly one state. Its lookup methods return that state for any id, without checking that the id's connection part matches the connection that registered it:

public synchronized TransportConnectionState lookupConnectionState(ConsumerId id) {
    TransportConnectionState cs = connectionState;
    if (cs == null) {
        throw new IllegalStateException(
                "Cannot lookup a consumer from a connection that had not been registered: "
                    + id.getParentId().getParentId());
    }
    return cs;
}

public synchronized TransportConnectionState lookupConnectionState(ConnectionId connectionId) {
    TransportConnectionState cs = connectionState;
    return cs;
}

The ProducerId, SessionId and String overloads follow the same pattern, and registerConnectionState stores whatever ConnectionId it is given without comparing it to the state's ConnectionInfo. As a result, an authenticated client can open sessions and consumers whose ids name another connection. The broker accepts them under the attacker's own security context, but the destination and subscription logic sees the victim's connection id. This lets the attacker:

  • consume from a temporary queue or topic owned by the victim, because the broker-side check that only the creating connection may consume from a temporary destination compares against the spoofed connection id;
  • register a consumer with the same ConsumerId as one of the victim's consumers. The duplicate is only logged, and the attacker's later RemoveInfo or disconnect removes the victim's live subscription;
  • send a MessageAck naming the victim's ConsumerId, which acknowledges and permanently deletes a message the victim has received but not yet acknowledged.

TransportConnection.processConsumerControl has the same gap for consumer control commands. It passes the result of getConsumerBrokerExchange to the broker even when no consumer with that id was ever registered on the connection:

public Response processConsumerControl(ConsumerControl control) throws Exception {
    ConsumerBrokerExchange consumerExchange = getConsumerBrokerExchange(control.getConsumerId());
    broker.processConsumerControl(consumerExchange, control);
    return null;
}

Exploitation needs a client that can authenticate to the broker and send OpenWire commands that carry the victim's connection id.

‍

Mitigation

Inactive versions of Apache ActiveMQ Classic are End-of-Life and will not receive updates to address this issue. For more information, see here.

Users of the affected components should apply one of the following mitigations:

  • Upgrade affected applications to a currently supported release of Apache ActiveMQ Classic that contains the fix.
  • Leverage a commercial support partner like HeroDevs for post-EOL security support.

Credits

zerovuln labs (finder)

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
High
ID
CVE-2026-108946
PROJECT Affected
ActiveMQ
Versions Affected
<5.19.12, >=6.0.0 <6.3.3
NES Versions Affected
Published date
November 9, 2026
≈ Fix date
November 6, 2026
Category
Authorization Bypass
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
NES for Apache ActiveMQ
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.