# Apache ActiveMQ — CWE-407 Disclosure Brief

**Project:** Apache ActiveMQ
**Disclosure date:** 2026-03-27
**Severity:** HIGH
**Speedup:** varies with n²
**Status:** PATCHED

---

## Finding

Apache ActiveMQ's `Topic` class in `activemq-broker` uses `CopyOnWriteArrayList.contains()` for subscriber deduplication at three separate locations (lines 151, 167, and 293 of `Topic.java`). `CopyOnWriteArrayList.contains()` is an O(n) linear scan; called inside subscription management loops, it produces O(n²) total behavior as subscriber counts grow. The correct fix is a parallel `ConcurrentHashMap.newKeySet()` for O(1) concurrent membership testing.

## The Defect(s)

| ID | Location | Pattern | Complexity |
|----|----------|---------|------------|
| activemq-0001 | `activemq-broker/.../region/Topic.java:151,167,293` | `CopyOnWriteArrayList.contains()` O(n²) subscriber dedup at three call sites | O(n²) |

## Complexity Proof

Let n = number of current subscribers on the Topic.

`CopyOnWriteArrayList.contains()` iterates the underlying array copy linearly. Called in subscription management to check for duplicates, at step i (when i subscribers exist) each check costs O(i):

```
Subscriber 1 added: contains() scans 0 entries
Subscriber 2 added: contains() scans 1 entry
...
Subscriber n added: contains() scans n-1 entries
Total (per call site): n(n-1)/2 = O(n²)
Three call sites: 3 × n(n-1)/2 = O(n²) (3× constant factor)
```

Additionally, `CopyOnWriteArrayList.contains()` creates a snapshot copy of the array on each read in concurrent scenarios, adding allocation pressure. A `ConcurrentHashMap.newKeySet()` provides O(1) amortized `contains()` and `add()` with full thread safety.

For n = 1,000 subscribers, the defective path performs ~1.5M comparisons across three sites; the fixed path performs ~3,000 hash lookups.

## Impact

ActiveMQ topics with many subscribers — publish/subscribe messaging topologies, fan-out event buses, financial market data distribution, IoT sensor feeds — experience quadratic subscription management time. The defect affects both the initial subscription setup and the dedup checks that run during subscription refresh and reconnect events. ActiveMQ is a foundational messaging broker in enterprise Java environments; the defect is in the core `Topic` region implementation shared by all JMS topic consumers.

High-subscriber scenarios are common: a single ActiveMQ topic can serve hundreds of microservice instances or IoT device connections. Broker restart events, rolling deployments, and network partitions that trigger mass reconnects all invoke the affected dedup paths simultaneously.

## The Fix

Add a parallel `ConcurrentHashMap.newKeySet()` as a companion to the existing `CopyOnWriteArrayList` subscriber list (or replace the list entirely if ordering is not required). Replace all three `CopyOnWriteArrayList.contains()` calls with `Set.contains()` from the concurrent key set. Keep `add()` and `remove()` synchronized between the list and set.

## Patch

```diff
- private final CopyOnWriteArrayList<Subscription> subscribers =
-     new CopyOnWriteArrayList<>();
+ private final CopyOnWriteArrayList<Subscription> subscribers =
+     new CopyOnWriteArrayList<>();
+ private final Set<Subscription> subscriberSet =
+     ConcurrentHashMap.newKeySet();

  // Topic.java:151
- if (!subscribers.contains(sub)) {
+ if (subscriberSet.add(sub)) {
      subscribers.add(sub);
  }

  // Topic.java:167
- if (!subscribers.contains(sub)) {
+ if (subscriberSet.add(sub)) {
      subscribers.add(sub);
  }

  // Topic.java:293
- if (subscribers.contains(sub)) {
-     subscribers.remove(sub);
- }
+ if (subscriberSet.remove(sub)) {
+     subscribers.remove(sub);
+ }
```

## What We Ask

Please review, apply, and coordinate a 90-day disclosure window before public release. Reply to security@undefect.com.

---

*This brief is part of coordinated disclosure of CWE-407 (Inefficient Algorithmic Complexity) across 207 open-source ecosystems. Full report: https://undefect.com*
