Remediation Guides

How to Fix CVE-2023-46604: Apache ActiveMQ OpenWire Remote Code Execution

26 September 2026 8 min read

CVE-2023-46604 is a critical remote code execution flaw in the Java OpenWire protocol marshaller used by Apache ActiveMQ Classic. Anyone who can reach an OpenWire port (TCP 61616 by default) can make the broker run arbitrary commands. Fix it by upgrading brokers and Java client jars to 5.15.16, 5.16.7, 5.17.6, 5.18.3 or later, and firewalling the port.

Because attackers used this flaw in ransomware attacks within days of the fix, an exposed broker needs one more step than most findings: check it for signs of compromise before you call it clean.

What the scanner is actually detecting

In Nessus the finding is titled Apache ActiveMQ RCE (CVE-2023-46604), plugin ID 186650, in the Misc. family, rated Critical (CVSS v3 9.8). It is a remote check: it depends on Tenable’s ActiveMQ listening port detection and runs against the detected ActiveMQ service or TCP 61616. Per Tenable’s description, it fires when the ActiveMQ version the service reports is earlier than a fixed release. It does not see client jars inside your applications, so a clean Nessus result does not prove your Java clients are patched.

Apache’s advisory (tracked as AMQ-9370) covers the broker, the Java OpenWire client and the Legacy OpenWire Module (activemq-openwire-legacy):

Branch Affected First fixed release
5.18 5.18.0 to 5.18.2 5.18.3
5.17 5.17.0 to 5.17.5 5.17.6
5.16 5.16.0 to 5.16.6 5.16.7
5.15 and older every release before 5.15.16 5.15.16

The root cause, per Rapid7’s analysis, is that the marshaller instantiates whatever class name an ExceptionResponse command carries without checking that it is an exception. Public exploits pass Spring’s ClassPathXmlApplicationContext with a URL, so the broker fetches attacker-hosted XML and runs the commands in it. The fix adds a check that the class derives from Throwable.

Real-world risk

This one is not theoretical. Rapid7 observed exploitation starting October 27, 2023, in which the broker’s Java process launched commands that attempted to deploy HelloKitty ransomware. CISA added the CVE to its Known Exploited Vulnerabilities catalog on November 2, 2023, marked as known to be used in ransomware campaigns (see our explainer on how the CISA KEV catalog works). Tenable lists exploits in Metasploit (“Apache ActiveMQ Unauthenticated Remote Code Execution”) and Core Impact.

  • Default exposure. The stock conf/activemq.xml binds the OpenWire connector to tcp://0.0.0.0:61616, so it listens on every interface. Commands run as the account the broker runs under.
  • No credentials needed. The CVSS vector requires no privileges, because the flaw triggers while the broker decodes the incoming command. Broker authentication is not a mitigation.
  • Reachability decides urgency. Treat a broker that was internet-reachable while unpatched as possibly compromised. One reachable only from application servers is lower risk, but not safe from a compromised neighbor. Keeping brokers off the internet is a core part of external attack surface management scope.
  • Clients. Attacking a Java client requires a malicious or impersonated broker, which is less likely, but Apache still recommends upgrading clients.

How to confirm it on the host

On Linux, adjust /opt/activemq to your install path:

# Is a broker running, and is OpenWire listening?
ps -ef | grep '[a]ctivemq.jar'
sudo ss -ltnp | grep ':61616'

# Installed version (prints "ActiveMQ 5.x.y")
/opt/activemq/bin/activemq --version
ls /opt/activemq/lib | grep -E '^activemq-(broker|client|openwire-legacy)-'
grep 'is starting' /opt/activemq/data/activemq.log

# Every connector; tcp, ssl, nio and auto schemes all speak OpenWire
grep -n '<transportConnector' /opt/activemq/conf/activemq.xml

On Windows, the service wrapper that ships with ActiveMQ registers a service named ActiveMQ (adjust the install path):

Get-Service ActiveMQ
Get-NetTCPConnection -LocalPort 61616 -State Listen
Get-ChildItem "C:apache-activemqlib" -Filter "activemq-*.jar" | Select-Object Name
Select-String -Path "C:apache-activemqdataactivemq.log" -Pattern "is starting"

From another machine, you can see the version the broker announces: it sends its wire format settings, including a ProviderVersion field, as soon as a client connects. The line printed after ProviderVersion is the version:

timeout 5 bash -c 'cat < /dev/tcp/BROKER_IP/61616' | strings | grep -A1 ProviderVersion

Find Java clients the scanner cannot see, including jars nested inside Spring Boot style fat jars:

find / -xdev ( -name 'activemq-client-*.jar' -o -name 'activemq-all-*.jar' -o -name 'activemq-openwire-legacy-*.jar' ) 2>/dev/null
unzip -l app.jar | grep activemq-client
mvn dependency:tree -Dincludes=org.apache.activemq

If the broker was reachable while unpatched, look for signs of exploitation. Search the logs for the gadget class, and list child processes of the broker JVM (a healthy broker normally has none):

grep -l ClassPathXmlApplicationContext /opt/activemq/data/activemq.log*
ps -o pid,user,cmd --ppid "$(pgrep -f activemq.jar | head -1)"

On Windows, review EDR or Sysmon process creation history for java.exe starting cmd.exe, powershell.exe or msiexec.exe, the pattern Rapid7 documented.

How to fix it

Step 1: contain the OpenWire port now

Allow the port only from the application servers and brokers that need it. With firewalld (replace the subnet):

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.20.0.0/24" port port="61616" protocol="tcp" accept'
sudo firewall-cmd --permanent --remove-port=61616/tcp
sudo firewall-cmd --reload

On Windows, create a scoped rule, then find and disable any broader allow rule (for the port or for java.exe), because a connection is allowed when any enabled allow rule matches it:

New-NetFirewallRule -DisplayName "ActiveMQ OpenWire (app subnet)" -Direction Inbound -Protocol TCP -LocalPort 61616 -RemoteAddress 10.20.0.0/24 -Action Allow
Get-NetFirewallPortFilter | Where-Object LocalPort -eq 61616 | Get-NetFirewallRule
Get-NetFirewallApplicationFilter | Where-Object Program -like '*java*' | Get-NetFirewallRule

You can also bind the connector to one interface instead of 0.0.0.0 in conf/activemq.xml, then restart the broker:

<transportConnector name="openwire" uri="tcp://10.20.0.15:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>

If no client uses OpenWire (everything connects over AMQP, STOMP or MQTT), Red Hat notes that disabling the OpenWire connector removes most of the risk. Networks of brokers use OpenWire, so check networkConnectors first. None of these steps is a fix; the vulnerable code stays until you upgrade.

Step 2: upgrade the broker

Any release in the table above clears this finding, but Apache’s download page lists the 5.15 to 5.18 branches as end of life. The supported branches are 5.19.x (Java 11, 17 or 21) and 6.3.x (Java 17, 21 or 25), and the ActiveMQ Classic security page lists later OpenWire advisories with 2026 CVE IDs. Moving to a current 5.19.x release is the smaller step for most 5.x estates, because 6.x requires Java 17 and moves to the Jakarta Messaging namespace.

For a tarball install on Linux:

V=5.19.11   # current 5.19.x at the time of writing; check the download page
OLD=/opt/apache-activemq-5.17.3
NEW=/opt/apache-activemq-$V
cd /opt
sudo curl -fO https://downloads.apache.org/activemq/$V/apache-activemq-$V-bin.tar.gz
sudo curl -fO https://downloads.apache.org/activemq/$V/apache-activemq-$V-bin.tar.gz.sha512
sha512sum -c apache-activemq-$V-bin.tar.gz.sha512
sudo tar -xzf apache-activemq-$V-bin.tar.gz

sudo $OLD/bin/activemq stop      # or stop your systemd unit
sudo tar -czf /root/activemq-pre-upgrade.tgz -C $OLD conf data
diff -ru $OLD/conf $NEW/conf     # port your changes; do not copy old files over blindly
sudo cp -a $OLD/data $NEW/
sudo $NEW/bin/activemq start     # then point your unit file or symlink at $NEW

Also copy any extra jars you added to lib/, such as JDBC drivers. On Windows, run an elevated PowerShell prompt:

$Old = "C:apache-activemq-5.17.3"
$New = "C:apache-activemq-5.19.11"
Get-FileHash .apache-activemq-5.19.11-bin.zip -Algorithm SHA512   # compare with the .sha512 file
Expand-Archive .apache-activemq-5.19.11-bin.zip -DestinationPath C:
Stop-Service ActiveMQ
New-Item -ItemType Directory C:activemq-pre-upgrade | Out-Null
Copy-Item -Recurse "$Oldconf","$Olddata" C:activemq-pre-upgrade
# merge your conf changes into $Newconf, copy $Olddata and extra lib jars to $New
& "$Oldbinwin64UninstallService.bat"
& "$Newbinwin64InstallService.bat"
Start-Service ActiveMQ

Brokers embedded in an application are fixed by upgrading the activemq-broker dependency; brokers bundled in a vendor product, by the vendor’s patch. If you run an Artemis-based broker with an OpenWire acceptor, follow your vendor’s advisory: Red Hat lists AMQ Broker 7 as affected when OpenWire is enabled.

Step 3: upgrade Java clients

Raise org.apache.activemq:activemq-client (or activemq-all) to a fixed version in each application. If a BOM manages the version, upgrade the BOM or override the managed version, then rebuild and redeploy.

Step 4: respond if you found indicators

Isolate the host, rebuild it from a known-good image, and rotate every secret the broker could read: credentials.properties, users.properties, jetty-realm.properties, jmx.password, and any database passwords in activemq.xml.

How to verify the fix and rescan

  1. bin/activemq –version and the lib/ jar names show a fixed release, and activemq.log shows the new version in the is starting line.
  2. The remote ProviderVersion check returns the new version. If it still shows the old one, the old JVM is still running.
  3. From a network that should not reach the broker, nc -zv -w 3 BROKER_IP 61616 (or Test-NetConnection BROKER_IP -Port 61616) fails.
  4. Rescan with Nessus. Plugin 186650 should stop reporting once the service reports a fixed version. If you only restricted the port, the finding stays open by design; record it as mitigated with an expiry date.

What can break and how to roll back

  • Java version. 5.19.x needs Java 11 or later, and 6.x needs Java 17 or later. Brokers still on Java 8 need a JDK upgrade first.
  • Configuration drift. Old jetty.xml or activemq.xml files can contain settings the new release rejects. Re-apply your changes to the new defaults and read activemq.log on first start.
  • Firewall scope. A missing subnet cuts off producers, consumers or broker network links.
  • Rollback. Stop the new broker, restore data from your backup into the old directory, and start the old release (on Windows, reinstall the old service with its InstallService.bat). Remove firewall rules with firewall-cmd –permanent –remove-rich-rule=’…’ or Remove-NetFirewallRule -DisplayName “…”. Rolling back reopens a KEV-listed flaw, so keep the port restricted while you do it.

Common false positive reasons

  • Vendor backports. A vendor build can carry the fix while reporting an older version number. Keep the vendor advisory and build details as evidence.
  • Stale results. A scan taken before the restart, or a broker upgraded on disk but never restarted, still reports the old version. Restart and rescan.
  • Port restricted. A firewall does not remove the vulnerable code, so the finding is valid; document it as mitigated rather than false.

FAQ

Does enabling broker authentication stop CVE-2023-46604?

No. The flaw triggers while the broker decodes the incoming OpenWire command, and it needs no credentials. Upgrade and restrict the port.

Is upgrading to 5.18.3 enough?

It clears this finding, but 5.18.x is end of life. A supported 5.19.x or 6.3.x release also receives fixes for later OpenWire advisories.

Do I need to update client applications?

Yes. Apache recommends upgrading both brokers and clients, and Nessus plugin 186650 only sees listening brokers, so clients need their own inventory.

Tracking this finding across many hosts

Across many brokers, the hard part is tracking which are upgraded, only firewalled, or still open. SITEY, a self-hosted vulnerability management platform, imports Nessus results from an uploaded .nessus export and supports per-finding retest for Nessus findings, so you can confirm plugin 186650 closes after each upgrade. Its AI triage can suggest false positives with evidence, such as a vendor backport, and a human makes the final call.

Sources

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing