This is a loaded nail gun locked in the server room, not a sniper round from the internet
CVE-2026-41044 is a broker-side RCE in Apache ActiveMQ Classic where an authenticated user can abuse the admin web console and Jolokia-exposed DestinationView MBean to smuggle an xbean-style broker name, trigger a VM transport, and make the broker JVM load attacker-controlled remote Spring XML. Affected ranges are all 5.x before 5.19.6 and 6.0.0 through 6.2.4 across apache-activemq, activemq-broker, and activemq-all.
paragraph 2: Vendor severity is defensible in a lab because the end state is full JVM code execution, but it overstates the real-world enterprise urgency. The decisive friction is that the attacker must first reach and authenticate to the management plane—the web console/Jolokia path—not merely the broker listener, and the vendor docs place those interfaces at localhost:8161 by default; that sharply narrows exposed population, which lines up with the tiny EPSS and lack of KEV or public exploitation evidence.
4 steps from start to impact.
Reach the admin surface with browser or curl
- Network reachability to the web console / Jolokia endpoint
- ActiveMQ Classic web apps enabled
- Attacker can reach TCP 8161 directly or through a proxy
- Vendor docs show the console and Jolokia examples on
localhost:8161, so many deployments keep it internal - A lot of enterprises segment broker admin ports away from user networks and the internet
- Public-facing exposure usually requires an explicit reverse proxy, NAT, or firewall exception
:8161/admin and :8161/api/jolokia; version detection is covered by Nessus plugin 311265 when the product version is visible.Authenticate to the console / Jolokia
xbean binding.- Valid credentials for the admin web application or equivalent management access
- Jolokia requests permitted after authentication
- Credential theft, password reuse, default creds, or prior foothold are all separate attacker work
- Modern SSO, PAM-backed auth, vault-managed secrets, and admin jump hosts materially reduce reachability
- If the service is only reachable from admin networks, this is already a post-initial-access path
/admin or /api/jolokia from unusual hosts, service accounts, or non-admin user segments. Web logs and reverse proxies should show the source IP even if the broker itself does not.Abuse DestinationView via Jolokia POST
DestinationView MBean to send a message that forces VM transport creation referencing that crafted name. This is the key weaponization step: the management feature becomes the trigger that dereferences attacker-controlled transport metadata.- Authenticated management access remains active
- Relevant ActiveMQ MBeans are exposed through Jolokia
- The attacker can issue POST requests to Jolokia or equivalent console actions
- This is not commodity one-shot RCE against a random listener; it depends on a specific management workflow
- Custom Jolokia policy restrictions can break the chain if exec operations are narrowed
- Some environments monitor or alert on unusual Jolokia
execactivity
POST /api/jolokia requests invoking ActiveMQ MBeans, especially DestinationView operations and suspicious broker names containing xbean, remote URIs, or transport parameters.Broker loads remote Spring XML and executes on the JVM
ResourceXmlApplicationContext instantiates singleton beans before BrokerService finishes validating the configuration. That ordering flaw is what turns config abuse into code execution, including bean factory methods that can reach Runtime.exec().- Broker can resolve the attacker-supplied remote Spring XML location
- The vulnerable version range is present
- Outbound network controls can block remote XML retrieval and kill many practical exploit paths
- If the broker has no egress to untrusted destinations, exploit reliability drops hard
- EDR may still catch the payload stage even if it cannot prevent the Spring bean instantiation
311265; distro package presence without a backport: Nessus 310128.The supporting signals.
| In-the-wild status | No reviewed source showed active exploitation, and CISA KEV did not list CVE-2026-41044 when checked against the catalog on 2026-05-29. |
|---|---|
| Proof-of-concept availability | No public PoC or Metasploit module was found in the reviewed sources; Tenable also marked exploit availability as "No known exploits are available." *This is an inference from the sources reviewed, not proof that no private exploit exists.* |
| EPSS | Reviewer-supplied EPSS is 0.00073. That is extremely low and consistent with a management-plane, post-auth bug; one public aggregator places it around the low-20s percentile *but that percentile was not confirmed from a primary FIRST feed in the reviewed sources*. |
| KEV status | Not KEV-listed as of 2026-05-29. Contrast that with the related ActiveMQ flaw CVE-2026-34197, which *has* KEV history—useful context that defenders should not blindly treat every Jolokia-related ActiveMQ CVE as equally urgent. |
| CVSS meaning | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H models easy exploitation *after* low privileges are obtained. The inflation comes from CVSS treating authenticated management access as only PR:L, while defenders know that access usually implies prior compromise, credential theft, or a very exposed admin plane. |
| Affected versions | apache-activemq, activemq-broker, and activemq-all are affected in all versions before 5.19.6 and 6.0.0 through 6.2.4. |
| Fixed versions / backports | Vendor fixes are 5.19.6 and 6.2.5. In the reviewed distro advisories, Ubuntu still showed Needs evaluation rather than a published backport, so do not assume distro packaging has quietly fixed this yet. |
| Exposure reality | ActiveMQ docs show the web console at http://localhost:8161/admin and the Jolokia management API at http://localhost:8161/api/jolokia/ by default. That means the exposed population is usually far smaller than a generic network RCE against the broker's client listener. |
| Disclosure | Publicly disclosed 2026-04-24; Apache shipped the fixing releases 2026-04-23. |
| Researcher / credit | Vendor advisory credits jsjcw as the finder. |
noisgate verdict.
The single most important downward pressure is that exploitation starts with authenticated access to the broker management plane, not with a blind shot at the normal messaging listener. That prerequisite implies either prior compromise, exposed admin infrastructure, or credential theft, which dramatically shrinks the reachable population despite the severe technical impact.
Why this verdict
- Downgrade for attacker position:
PR:Lhere really means *authenticated management access*. In enterprise terms that usually implies prior foothold, stolen creds, or an intentionally exposed admin plane, so I cut materially below the vendor 8.8 baseline. - Downgrade for reachable population: the vulnerable surface is the web console / Jolokia path on port
8161, not the ordinary broker traffic path. Vendor docs uselocalhost:8161for both admin and Jolokia examples, which means a lot of estates will have little or no internet-exposed population. - Keep it above LOW: once the chain is satisfied, impact is full broker JVM RCE with the potential to pivot through messaging infrastructure, secrets, and integration paths. This is still a serious post-auth compromise of a high-value service.
Why not higher?
There is no evidence in the reviewed sources of active exploitation, KEV status, or broadly available public weaponization. More importantly, the bug is gated by access to an authenticated management interface, which is a compounding friction point that CVSS under-penalizes in real enterprise environments.
Why not lower?
This is not a harmless admin bug or a narrow information leak: successful exploitation gives arbitrary code execution on the broker JVM. ActiveMQ brokers often sit on trusted internal paths and handle sensitive traffic, so when an attacker already has console access the blast radius can be meaningful.
What to do — in priority order.
- Fence off port 8161 — Restrict the web console and
/api/jolokiato admin jump hosts, VPN ranges, or a management VLAN only. For a MEDIUM verdict there is no mitigation SLA, but if any broker exposes 8161 beyond an admin enclave, close that gap immediately and still complete patching inside the 365-day remediation window. - Kill default and shared credentials — Rotate any local
jetty-realm.propertiescredentials, removeadmin/adminanywhere it still exists, and move to unique admin identities. This breaks the cheapest path into the management plane and should be done opportunistically now even though MEDIUM has no mitigation SLA. - Tighten Jolokia policy — Use a custom Jolokia security policy to narrow or deny dangerous MBean operations rather than leaving broad
execaccess overorg.apache.activemq:*. This directly attacks the exploit chain and is the best compensating control when you cannot patch immediately. - Block broker egress to untrusted URLs — The exploit path wants the broker to fetch attacker-controlled remote Spring XML. Enforce outbound allowlisting or at least deny direct internet egress from broker hosts so a planted malicious broker name cannot easily dereference external content.
- Alert on Jolokia exec abuse — Create detections for
POST /api/jolokiarequests invoking ActiveMQ MBeans, especiallyDestinationViewactions and suspicious strings likexbean, remote URLs, and transport parameters. This is cheap telemetry that catches both this bug and adjacent Jolokia abuse families.
- A WAF alone is weak here because many exploit paths are internal-only or come from already-authenticated admin sessions; the decisive control is network segmentation and auth hardening, not generic edge filtering.
- TLS only does nothing once the attacker is authenticated; encryption protects transit, not dangerous MBean operations.
- EDR alone is not enough. It may catch child-process execution or payload staging, but it does not remove the vulnerable management feature chain that leads to broker compromise.
- Focusing only on port 61616 misses the problem. This CVE rides the admin console / Jolokia path on
8161, not normal client messaging.
Crowdsourced verification payload.
Run this on the target ActiveMQ host or against an extracted install directory. Invoke it as python3 verify_cve_2026_41044.py /opt/activemq or point it at a JAR like python3 verify_cve_2026_41044.py /opt/activemq/lib/activemq-broker-6.2.4.jar; no admin rights are required if the install path is readable.
#!/usr/bin/env python3
# verify_cve_2026_41044.py
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=USAGE
import os
import re
import sys
import zipfile
import subprocess
from pathlib import Path
USAGE = "Usage: python3 verify_cve_2026_41044.py <ACTIVEMQ_HOME|jar-file|version-string>"
def norm_version(v):
if not v:
return None
v = v.strip()
m = re.search(r'(\d+)\.(\d+)\.(\d+)', v)
if not m:
return None
return tuple(int(x) for x in m.groups())
def version_to_str(vt):
return '.'.join(str(x) for x in vt) if vt else 'unknown'
def compare(a, b):
return (a > b) - (a < b)
def is_vulnerable(vt):
if vt is None:
return None
if compare(vt, (6, 0, 0)) >= 0 and compare(vt, (6, 2, 5)) < 0:
return True
if compare(vt, (5, 19, 6)) < 0:
return True
return False
def read_manifest_version(jar_path):
try:
with zipfile.ZipFile(jar_path, 'r') as zf:
for name in zf.namelist():
if name.upper() == 'META-INF/MANIFEST.MF':
data = zf.read(name).decode('utf-8', errors='ignore')
for line in data.splitlines():
if line.lower().startswith('implementation-version:'):
return line.split(':', 1)[1].strip()
except Exception:
return None
return None
def find_version_in_filenames(root):
patterns = [
r'activemq-(?:broker|all|client)-(?P<v>\d+\.\d+\.\d+)\.jar$',
r'apache-activemq-(?P<v>\d+\.\d+\.\d+)',
r'activemq-(?P<v>\d+\.\d+\.\d+)'
]
candidates = []
for base, _, files in os.walk(root):
for f in files:
for pat in patterns:
m = re.search(pat, f)
if m:
candidates.append(m.group('v'))
if candidates:
# Prefer highest parsed version found in the tree
parsed = [norm_version(c) for c in candidates]
parsed = [p for p in parsed if p is not None]
if parsed:
parsed.sort()
return version_to_str(parsed[-1])
return None
def run_activemq_version(home):
bin_candidates = [Path(home) / 'bin' / 'activemq', Path(home) / 'bin' / 'activemq.bat']
for candidate in bin_candidates:
if candidate.exists():
try:
if candidate.suffix.lower() == '.bat':
proc = subprocess.run([str(candidate)], capture_output=True, text=True, timeout=15, shell=True)
else:
proc = subprocess.run([str(candidate), '--version'], capture_output=True, text=True, timeout=15)
out = (proc.stdout or '') + '\n' + (proc.stderr or '')
m = re.search(r'(\d+\.\d+\.\d+)', out)
if m:
return m.group(1)
except Exception:
pass
return None
def extract_version(target):
p = Path(target)
# Raw version string
raw = norm_version(target)
if raw:
return version_to_str(raw), 'user-supplied version string'
# Jar file
if p.is_file() and p.suffix.lower() == '.jar':
mv = read_manifest_version(str(p))
if mv:
return mv, f'manifest in {p.name}'
m = re.search(r'(\d+\.\d+\.\d+)', p.name)
if m:
return m.group(1), f'filename {p.name}'
return None, f'could not extract version from {p}'
# Directory / install root
if p.is_dir():
v = run_activemq_version(str(p))
if v:
return v, f'{p}/bin/activemq'
lib = p / 'lib'
if lib.is_dir():
for jar_name in ['activemq-broker', 'activemq-all', 'activemq-client']:
jars = sorted(lib.glob(f'{jar_name}-*.jar'))
for jar in jars:
mv = read_manifest_version(str(jar))
if mv:
return mv, f'manifest in {jar.name}'
m = re.search(r'(\d+\.\d+\.\d+)', jar.name)
if m:
return m.group(1), f'filename {jar.name}'
fv = find_version_in_filenames(str(p))
if fv:
return fv, f'filenames under {p}'
return None, f'could not determine version from {p}'
return None, 'target path not found'
def main():
if len(sys.argv) != 2:
print('UNKNOWN - ' + USAGE)
sys.exit(3)
target = sys.argv[1]
version_str, source = extract_version(target)
vt = norm_version(version_str) if version_str else None
if vt is None:
print(f'UNKNOWN - Unable to determine ActiveMQ version ({source})')
sys.exit(2)
vuln = is_vulnerable(vt)
if vuln is None:
print(f'UNKNOWN - Parsed version {version_to_str(vt)} but could not classify')
sys.exit(2)
if vuln:
print(f'VULNERABLE - ActiveMQ version {version_to_str(vt)} from {source} matches CVE-2026-41044 affected ranges (<5.19.6 or 6.0.0-6.2.4)')
sys.exit(1)
else:
print(f'PATCHED - ActiveMQ version {version_to_str(vt)} from {source} is outside the CVE-2026-41044 affected ranges')
sys.exit(0)
if __name__ == '__main__':
main()
If you remember one thing.
8161 is reachable from anything beyond an admin enclave. For this MEDIUM reassessment there is no noisgate mitigation SLA — go straight to the 365-day remediation window; that means use exposure reduction as smart hygiene now, but finish the actual upgrade to 5.19.6 or 6.2.5+ within the noisgate remediation SLA, which from 2026-05-29 lands no later than 2027-05-29.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.