The organizations hit hardest were those running ActiveMQ with no network segmentation and no patches applied. But patch status aside, many were also running their brokers with default credentials and no authentication, i.e., a configuration that creates a second, entirely separate attack surface even when the RCE vulnerability is patched.
This ActiveMQ security hardening guide covers the complete discipline: from patching the known CVEs to configuring transport layer security, JAAS authentication, LDAP authentication, destination-level authorization, admin console hardening security, and network isolation. We cover both Apache ActiveMQ® and Apache Artemis™. Security is the one area where “good enough” is not an engineering position, it is a liability.
Layer Zero: Patch First
Before any security hardening configuration is worth discussing, patch status takes priority.
CVE-2023-46604: Critical RCE (CVSS 10.0)
The Java OpenWire protocol marshaller in Apache ActiveMQ® was vulnerable to Remote Code Execution. An attacker with network access to a Java-based OpenWire broker or client could run arbitrary shell commands by manipulating serialized class types in the OpenWire protocol, causing the broker to instantiate any class on the classpath. The attack required no authentication and was exploitable via port 61616.
Users of both Apache ActiveMQ® and Apache Artemis™ brokers are recommended to upgrade. Users of any Java-based OpenWire client (e.g., Maven dependency on activemq-client) are also recommended to upgrade regardless of which broker they are using.
Fixed versions: Apache ActiveMQ® 5.15.16, 5.16.7, 5.17.6, 5.18.3, and all later releases.
If immediate patching is not possible, the emergency mitigation is to firewall port 61616 to allow only known, trusted client IP addresses. This does not eliminate the vulnerability but removes unauthenticated internet exposure, which is how the ransomware campaigns operate.
CVE-2022-41678: Jolokia Authenticated RCE
A separate vulnerability in Apache ActiveMQ®: Jolokia, the JMX HTTP bridge that powers the web console, allowed authenticated users to perform Remote Code Execution via the web console. This underscores why default admin credentials are not just a convenience issue: an attacker who obtains the default admin/admin credentials gains RCE capability against unpatched brokers.
Hardening rule: treat CVE patches and credential management as the same category of security hardening requirement. Neither is optional.
Layer 1: Transport Security: TLS for All Connections
Apache ActiveMQ®: ssl:// and mqtt+nio+ssl://
Transport layer security encrypts all message traffic in transit and, when mutual TLS is configured, authenticates client certificates before the JAAS layer even runs. Properly configured transport layer security prevents eavesdropping, man-in-the-middle attacks, and protects credentials transmitted during broker authentication.
| <!– activemq.xml — production TLS configuration –> <broker xmlns=”http://activemq.apache.org/schema/core” brokerName=”prod-broker”> <!– SSL Context: configure once, applies to all SSL transports –> <sslContext> <sslContext keyStore=”/etc/activemq/certs/broker.ks” keyStorePassword=”${ssl.keystore.password}” trustStore=”/etc/activemq/certs/broker.ts” trustStorePassword=”${ssl.truststore.password}” keyStoreKeyPassword=”${ssl.key.password}”/> </sslContext> <transportConnectors> <!– Disable plaintext OpenWire — force all clients to TLS –> <!– <transportConnector name=”openwire” uri=”tcp://0.0.0.0:61616″/> –> <!– TLS OpenWire on standard port 61617 –> <transportConnector name=”ssl” uri=”ssl://0.0.0.0:61617?maximumConnections=2000 &transport.enabledProtocols=TLSv1.2,TLSv1.3 &transport.needClientAuth=false”/> <!– TLS MQTT on standard secure port 8883 –> <transportConnector name=”mqtt+ssl” uri=”mqtt+nio+ssl://0.0.0.0:8883 ?maximumConnections=5000 &transport.enabledProtocols=TLSv1.2,TLSv1.3″/> </transportConnectors> </broker> |
Password externalization: Never embed keystore passwords as plaintext in activemq.xml. Use Spring property placeholders as shown (${ssl.keystore.password}), resolved from an external credentials.properties file with OS-level file permissions restricting read access to the activemq process user only. From Apache ActiveMQ® 5.4.1, encrypted passwords are supported via the Jasypt integration.
transport.enabledProtocols=TLSv1.2,TLSv1.3: Explicitly restrict transport layer security to TLS 1.2 and 1.3. TLS 1.0 and 1.1 are deprecated in all major security hardening standards and compliance frameworks, they should never be offered by a production broker.
Keystore Setup
| # 1. Generate broker keypair (2048-bit RSA minimum; 4096-bit for high-security) keytool -genkey -alias broker -keyalg RSA -keysize 4096 \ -validity 730 -keystore /etc/activemq/certs/broker.ks \ -storepass “${STOREPASS}” \ -dname “CN=activemq-broker.internal.example.com,O=ACME Corp,C=US” # 2. Export broker certificate keytool -export -alias broker \ -keystore /etc/activemq/certs/broker.ks \ -storepass “${STOREPASS}” \ -file /etc/activemq/certs/broker.crt # 3. Create client truststore importing broker’s CA certificate keytool -import -alias broker-ca \ -keystore /etc/activemq/certs/client.ts \ -storepass “${STOREPASS}” \ -file /path/to/ca.crt -noprompt # 4. Set restrictive file permissions chmod 600 /etc/activemq/certs/*.ks chmod 600 /etc/activemq/certs/*.ts chown activemq:activemq /etc/activemq/certs/* |
Apache Artemis™: TLS Acceptor
| <!– broker.xml — Artemis TLS acceptors –> <acceptors> <!– Disable plaintext –> <!– <acceptor name=”all-protocols”>tcp://0.0.0.0:61616</acceptor> –> <!– TLS for all protocols –> <acceptor name=”tls”>tcp://0.0.0.0:61617 ?ssl=true &keyStorePath=/etc/activemq/certs/broker.ks &keyStorePassword=${ssl.keystore.password} &trustStorePath=/etc/activemq/certs/broker.ts &trustStorePassword=${ssl.truststore.password} &enabledProtocols=TLSv1.2,TLSv1.3 &needClientAuth=false</acceptor> <!– MQTT TLS –> <acceptor name=”mqtt-tls”>tcp://0.0.0.0:8883 ?protocols=MQTT &ssl=true &keyStorePath=/etc/activemq/certs/broker.ks &keyStorePassword=${ssl.keystore.password} &enabledProtocols=TLSv1.2,TLSv1.3</acceptor> </acceptors> |
We covered the MQTT-specific TLS setup in detail in our post on ActiveMQ MQTT Protocol Setup Guide.
For broker-to-broker TLS on Apache ActiveMQ® network connectors, we covered credential requirements in our Network of Brokers Configuration.
Running ActiveMQ Without TLS or Authentication in Production?
Running ActiveMQ Without TLS or Authentication in Production? Every day, a production broker runs with open plaintext ports and default credentials is a day a breach is one network scan away. meshIQ’s security advisory team can assess your current configuration and deliver a hardening plan tailored to your compliance requirements.
Request a Security AuditLayer 2: Authentication: JAAS for Apache ActiveMQ®
Choosing the Right Authentication Plugin
Apache ActiveMQ® offers three authentication plugin options:
| Plugin | Use Case | Production Appropriate? |
| simpleAuthenticationPlugin | Dev/test, small deployments, plaintext credentials in XML | No, credentials in XML are visible in version control and process listings |
| jaasAuthenticationPlugin + PropertiesLoginModule | Small-to-medium production; credentials in external files | Yes, with appropriate file permissions |
| jaasAuthenticationPlugin + LDAPLoginModule | Enterprise; central user management, Active Directory | Yes, recommended for enterprise deployments |
Never use simpleAuthenticationPlugin in production. It embeds credentials directly in activemq.xml in plaintext, which is typically committed to version control and visible in process listings.
Production JAAS Configuration: PropertiesLoginModule
| <!– activemq.xml — JAAS authentication + authorization –> <broker xmlns=”http://activemq.apache.org/schema/core”> <plugins> <!– JAAS authentication: points to login.config domain name –> <jaasAuthenticationPlugin configuration=”activemq-production”/> <!– Destination-level authorization –> <authorizationPlugin> <map> <authorizationMap> <authorizationEntries> <!– Service accounts: scoped to specific destinations –> <authorizationEntry queue=”orders.>” read=”orders-consumers” write=”orders-producers” admin=”admins”/> <authorizationEntry queue=”payments.>” read=”payments-consumers” write=”payments-producers” admin=”admins”/> <authorizationEntry topic=”events.>” read=”event-subscribers” write=”event-publishers” admin=”admins”/> <!– Admin: full access for management operations –> <authorizationEntry queue=”>” read=”admins” write=”admins” admin=”admins”/> <authorizationEntry topic=”>” read=”admins” write=”admins” admin=”admins”/> <!– Advisory topics: MUST have permissive access –> <!– Locking this down breaks connections and NoB –> <authorizationEntry topic=”ActiveMQ.Advisory.>” read=”admins,services” write=”admins,services” admin=”admins,services”/> </authorizationEntries> <!– Temporary destinations: restrict to admin only –> <tempDestinationAuthorizationEntry> <tempDestinationAuthorizationEntry read=”admins,services” write=”admins,services” admin=”admins”/> </tempDestinationAuthorizationEntry> </authorizationMap> </map> </authorizationPlugin> </plugins> </broker> # login.config (typically in $ACTIVEMQ_HOME/conf/ or on classpath) activemq-production { org.apache.activemq.jaas.PropertiesLoginModule required org.apache.activemq.jaas.properties.user=”users.properties” org.apache.activemq.jaas.properties.group=”groups.properties” reload=true; }; # users.properties # Format: username=password (consider encrypted passwords via Jasypt) orders-svc=changeme-orders payments-svc=changeme-payments admin=changeme-admin # groups.properties # Format: groupname=username1,username2 admins=admin orders-producers=orders-svc orders-consumers=orders-svc payments-producers=payments-svc payments-consumers=payments-svc services=orders-svc,payments-svc |
reload=true in login.config: From Apache ActiveMQ® 5.12 onward, properties files are NOT reloaded automatically unless reload=true is set. Without it, a password change requires a broker restart. Set reload=true to enable live credential updates without restart, important for rotating credentials as part of ongoing hardening security operations.
The Advisory Topic Authorization Requirement
This is the most frequently encountered authorization misconfiguration in ActiveMQ security hardening. When authorization is enabled, teams often lock down all destinations using a blanket policy, including ActiveMQ.Advisory.>.
The result: client connections begin failing with javax.jms.JMSException: Not authorized even though the user has permission for their actual destination.
Advisory topics are used by ActiveMQ for connection management, temporary destination tracking, and the coordination of a network of brokers. They must have permissive authorization for all roles that connect to the broker. The configuration above handles this correctly with the read=”admins,services” entry on ActiveMQ.Advisory.>. Never use admin=”*” on advisory topics without also including your service account roles.
Apache ActiveMQ®: LDAP Authentication for Enterprise
For organizations with Active Directory or LDAP infrastructure, LDAP authentication via LDAPLoginModule centralizes credential management and eliminates the need to manage properties files per broker, making it the recommended ActiveMQ security hardening approach at enterprise scale:
| <!– activemq.xml — JAAS LDAP plugin –> <plugins> <jaasAuthenticationPlugin configuration=”LdapConfiguration”/> <!– authorizationPlugin goes here as above –> </plugins> # login.config — LDAP module LdapConfiguration { org.apache.activemq.jaas.LDAPLoginModule required debug=false initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory connectionURL=”ldap://ldap.internal.example.com:389″ connectionUsername=”cn=activemq-bind,ou=Services,dc=example,dc=com” connectionPassword=”{SSHA}bindpassword” connectionProtocol=s authentication=simple userBase=”ou=Users,ou=ActiveMQ,ou=systems,dc=example,dc=com” userSearchMatching=”uid={0}” userSearchSubtree=true roleBase=”ou=Groups,ou=ActiveMQ,ou=systems,dc=example,dc=com” roleName=cn roleSearchMatching=”(member={0})” roleSearchSubtree=true; }; |
Layer 2: Authentication: Apache Artemis™ Security Settings
Artemis ships with security enabled by default via ActiveMQJAASSecurityManager. The default configuration uses PropertiesLoginModule reading from artemis-users.properties and artemis-roles.properties in the instance’s etc/ directory.
| # etc/artemis-users.properties — REPLACE ALL DEFAULT VALUES # Default content (e.g., admin = ENC(password)) is publicly known admin = changeme-admin orders-svc = changeme-orders payments-svc = changeme-payments # etc/artemis-roles.properties admins = admin orders-producers = orders-svc orders-consumers = orders-svc payments-producers = payments-svc payments-consumers = payments-svc <!– broker.xml — Artemis security settings (9 permission types vs Classic’s 3) –> <security-settings> <!– Admins: full access to everything –> <security-setting match=”#”> <permission type=”createNonDurableQueue” roles=”admins”/> <permission type=”deleteNonDurableQueue” roles=”admins”/> <permission type=”createDurableQueue” roles=”admins”/> <permission type=”deleteDurableQueue” roles=”admins”/> <permission type=”createAddress” roles=”admins”/> <permission type=”deleteAddress” roles=”admins”/> <permission type=”consume” roles=”admins”/> <permission type=”browse” roles=”admins”/> <permission type=”send” roles=”admins”/> <permission type=”manage” roles=”admins”/> </security-setting> <!– Orders namespace: scoped producer + consumer access –> <security-setting match=”orders.#”> <permission type=”createNonDurableQueue” roles=”admins,orders-consumers”/> <permission type=”createDurableQueue” roles=”admins,orders-consumers”/> <permission type=”consume” roles=”admins,orders-consumers”/> <permission type=”browse” roles=”admins,orders-consumers”/> <permission type=”send” roles=”admins,orders-producers”/> </security-setting> <!– Payments namespace: scoped access –> <security-setting match=”payments.#”> <permission type=”createNonDurableQueue” roles=”admins,payments-consumers”/> <permission type=”createDurableQueue” roles=”admins,payments-consumers”/> <permission type=”consume” roles=”admins,payments-consumers”/> <permission type=”browse” roles=”admins,payments-consumers”/> <permission type=”send” roles=”admins,payments-producers”/> </security-setting> </security-settings> |
Apache ActiveMQ® vs Apache Artemis™ permission types: Apache ActiveMQ® uses 3 permission types (read, write, admin). Artemis uses 9 (createNonDurableQueue, deleteNonDurableQueue, createDurableQueue, deleteDurableQueue, createAddress, deleteAddress, send, consume, browse, manage). Artemis’s granularity enables enforcing the principle of least privilege at a much finer level, a key advantage for security hardening in high-compliance environments.
Layer 3: Admin Console Hardening
The ActiveMQ web console (Hawtio/Jolokia) is a common attack vector. CVE-2022-41678 demonstrated that authenticated console access can lead to RCE. The default credentials (admin/admin) are publicly known, replacing them is the first step of any hardening security exercise.
Apache ActiveMQ®: Jetty Realm Hardening
| # conf/jetty-realm.properties — change IMMEDIATELY on deployment # Format: username: password, role admin: changeme-admin, admin viewer: changeme-viewer, viewer <!– conf/jetty.xml — restrict web console to internal interfaces –> <Call name=”addConnector”> <Arg> <New class=”org.eclipse.jetty.server.ServerConnector”> <Arg><Ref refid=”Server”/></Arg> <!– Bind to loopback or internal management interface only –> <!– Never bind to 0.0.0.0 in production –> <Set name=”host”>127.0.0.1</Set> <Set name=”port”>8161</Set> </New> </Arg> </Call> |
Restricting Jolokia Access
Jolokia (the JMX HTTP bridge) is the most sensitive component of the web console. If you do not need external JMX access, restrict Jolokia to localhost only and consider disabling HTTP access entirely in favor of direct JMX:
| <!– conf/jolokia-access.xml — restrict to localhost –> <restrict> <remote> <!– Only allow access from loopback –> <host>127.0.0.1</host> <host>::1</host> </remote> <cors> <!– Restrict CORS origins –> <allow-origin>http://localhost:8161</allow-origin> </cors> </restrict> |
Secure JMX Access Without Exposing the Web Console
meshIQ Console provides secure, role-based monitoring and management of your ActiveMQ brokers, without requiring the Jolokia HTTP bridge to be internet-accessible. All management operations go through meshIQ’s secure API layer.
See It in ActionLayer 4: Network Hardening
Configuration is the foundation, but network architecture is the perimeter. Genuine security hardening requires both.
Port Restriction
| Port | Protocol | Default Exposure | Hardened Exposure |
| 61616 | OpenWire (TCP) | 0.0.0.0 (all interfaces) | Internal app subnet only; never internet-facing |
| 61617 | OpenWire (SSL) | Not enabled by default | Internal app subnet only |
| 1883 | MQTT | Not enabled by default | IoT device network only; never plaintext in prod |
| 8883 | MQTT (TLS) | Not enabled by default | IoT device network only |
| 5672 | AMQP | Not enabled by default | Internal app subnet only |
| 8161 | Web console (HTTP) | 0.0.0.0 | Management subnet only; bind to 127.0.0.1 or VPN |
| 1099 | JMX/RMI | 0.0.0.0 | Management subnet only; bind to internal interface |
The CVE-2023-46604 lesson: port 61616 exposed to the internet is a critical security hardening failure. Treat it the same as exposing a database port directly to the internet, never acceptable, regardless of the authentication configuration.
Disabling Unused Transport Connectors
Every enabled transport connector is an attack surface. Disabling connectors for protocols your applications do not use is one of the simplest hardening security wins available:
| <!– activemq.xml — only enable what you actually use –> <transportConnectors> <!– Only TLS OpenWire — all other connectors disabled –> <transportConnector name=”ssl” uri=”ssl://0.0.0.0:61617″/> <!– Add MQTT only if needed: –> <!– <transportConnector name=”mqtt+ssl” uri=”mqtt+nio+ssl://0.0.0.0:8883″/> –> </transportConnectors> |
advisorySupport and Security
If you have locked down advisory topics completely with the authorization plugin, you may observe client connection failures even from properly authorized clients. As we noted in the authorization configuration above, ActiveMQ.Advisory.> must have permissive access for all connecting service accounts.
An alternative for purely static deployments (no network of brokers, no dynamic consumer tracking) is to disable advisorySupport on the broker element: <broker advisorySupport=”false”>. This eliminates advisory topics entirely but also disables the NoB dynamic discovery mechanism. Only consider this if you have verified your applications do not depend on advisory messages.
The ActiveMQ Security Hardening Checklist
Apply every item before a production deployment. This security hardening checklist addresses the most critical risks first.
Critical (do immediately):
- Patch to CVE-2023-46604 fixed version (5.15.16+ / 5.16.7+ / 5.17.6+ / 5.18.3+)
- Change all default credentials (admin/admin console, system/manager broker, artemis-users.properties)
- Firewall port 61616 to trusted client subnets only, never internet-facing
- Enable TLS on all transport connectors; disable plaintext equivalents
- Restrict TLS to versions 1.2 and 1.3 per current security hardening standards
High (complete within first sprint):
- Replace simpleAuthenticationPlugin with jaasAuthenticationPlugin + LDAP authentication
- Configure authorizationPlugin with least-privilege destination entries per service account
- Ensure ActiveMQ.Advisory.> has permissive authorization for all service roles
- Bind web console (port 8161) to internal management interface; never 0.0.0.0
- Restrict Jolokia to localhost only via jolokia-access.xml
Operational (ongoing):
- Externalize keystore passwords, never plaintext in activemq.xml
- Set reload=true in login.config for live credential rotation without restart
- Disable unused transport connectors (STOMP, AMQP, MQTT if not used)
- Review security advisories at activemq.apache.org/security-advisories on each patch cycle
- Enable JMX authentication (-Dcom.sun.jmx.remote.authenticate=true)
Security Is Not a One-Time Configuration
ActiveMQ security hardening is not a checkbox, it is an ongoing practice. CVE-2023-46604 was discovered in a broker that had been running in production for years, in organizations with other security controls in place. The specific failure was not firewall coverage, unpatched software, or port exposure in isolation: the combination of all three made exploitation trivial.
This guide addresses all three categories: patching, configuration, and network isolation. Applying all of them, transport layer security on every connector, LDAP authentication for centralized credential management, and network segmentation aligned with security hardening standards, moves your broker from an easily exploitable default configuration to a defense-in-depth architecture that requires an attacker to defeat multiple independent controls simultaneously.
meshIQ provides enterprise security hardening assessments for ActiveMQ deployments, covering configuration review, CVE exposure analysis, credential management, and compliance mapping for regulated industries.
Get your ActiveMQ security configuration reviewed → Request a Security Audit
Frequently Asked Questions
No. Apache ActiveMQ® ships with no authentication and known default credentials. Artemis ships with security enabled, but with default credentials that must be replaced immediately. Both require explicit ActiveMQ security hardening before any production deployment.
A CVSS 10.0 RCE vulnerability that allowed unauthenticated attackers to execute code via port 61616 through the OpenWire protocol. Exploited in HelloKitty ransomware campaigns in October 2023. Fix by upgrading to Apache ActiveMQ® 5.15.16, 5.16.7, 5.17.6, or 5.18.3 (or any later version). Emergency mitigation: firewall port 61616 to trusted subnets only.
In Apache ActiveMQ®, add a jaasAuthenticationPlugin to the broker’s plugins section and configure login.config with PropertiesLoginModule or, for enterprise environments, LDAP authentication via LDAPLoginModule. In Artemis, security is already enabled. Replace the default credentials in artemis-users.properties and configure security-settings in broker.xml.
In Apache ActiveMQ®, add an authorizationPlugin with authorizationEntry elements per destination pattern specifying read, write, and admin role lists. In Artemis, configure security-setting elements in broker.xml with granular permission types (send, consume, browse, createDurableQueue, etc.) per address pattern.
In Apache ActiveMQ®: conf/jetty-realm.properties (web console), conf/credentials.properties (broker connection credentials), and conf/users.properties (JAAS users). In Artemis: etc/artemis-users.properties. Never leave any default credentials in production. CVE-2022-41678 demonstrated that authenticated console access enables RCE on unpatched brokers.